[ Index ] |
PHP Cross Reference of Unnamed Project |
[Summary view] [Print] [Text view]
1 /* 2 YUI 3.17.2 (build 9c3c78e) 3 Copyright 2014 Yahoo! Inc. All rights reserved. 4 Licensed under the BSD License. 5 http://yuilibrary.com/license/ 6 */ 7 8 YUI.add('promise', function (Y, NAME) { 9 10 /** 11 Wraps the execution of asynchronous operations, providing a promise object that 12 can be used to subscribe to the various ways the operation may terminate. 13 14 When the operation completes successfully, call the Resolver's `resolve()` 15 method, passing any relevant response data for subscribers. If the operation 16 encounters an error or is unsuccessful in some way, call `reject()`, again 17 passing any relevant data for subscribers. 18 19 The Resolver object should be shared only with the code resposible for 20 resolving or rejecting it. Public access for the Resolver is through its 21 _promise_, which is returned from the Resolver's `promise` property. While both 22 Resolver and promise allow subscriptions to the Resolver's state changes, the 23 promise may be exposed to non-controlling code. It is the preferable interface 24 for adding subscriptions. 25 26 Subscribe to state changes in the Resolver with the promise's 27 `then(callback, errback)` method. `then()` wraps the passed callbacks in a 28 new Resolver and returns the corresponding promise, allowing chaining of 29 asynchronous or synchronous operations. E.g. 30 `promise.then(someAsyncFunc).then(anotherAsyncFunc)` 31 32 @module promise 33 @since 3.9.0 34 **/ 35 36 var Lang = Y.Lang, 37 slice = [].slice; 38 39 /** 40 A promise represents a value that may not yet be available. Promises allow 41 you to chain asynchronous operations, write synchronous looking code and 42 handle errors throughout the process. 43 44 This constructor takes a function as a parameter where you can insert the logic 45 that fulfills or rejects this promise. The fulfillment value and the rejection 46 reason can be any JavaScript value. It's encouraged that rejection reasons be 47 error objects 48 49 <pre><code> 50 var fulfilled = new Y.Promise(function (resolve) { 51 resolve('I am a fulfilled promise'); 52 }); 53 54 var rejected = new Y.Promise(function (resolve, reject) { 55 reject(new Error('I am a rejected promise')); 56 }); 57 </code></pre> 58 59 @class Promise 60 @constructor 61 @param {Function} fn A function where to insert the logic that resolves this 62 promise. Receives `resolve` and `reject` functions as parameters. 63 This function is called synchronously. 64 **/ 65 function Promise(fn) { 66 if (!(this instanceof Promise)) { 67 return new Promise(fn); 68 } 69 70 var resolver = new Promise.Resolver(this); 71 72 /** 73 A reference to the resolver object that handles this promise 74 75 @property _resolver 76 @type Object 77 @private 78 */ 79 this._resolver = resolver; 80 81 try { 82 fn.call(this, function (value) { 83 resolver.resolve(value); 84 }, function (reason) { 85 resolver.reject(reason); 86 }); 87 } catch (e) { 88 resolver.reject(e); 89 } 90 } 91 92 Y.mix(Promise.prototype, { 93 /** 94 Schedule execution of a callback to either or both of "fulfill" and 95 "reject" resolutions for this promise. The callbacks are wrapped in a new 96 promise and that promise is returned. This allows operation chaining ala 97 `functionA().then(functionB).then(functionC)` where `functionA` returns 98 a promise, and `functionB` and `functionC` _may_ return promises. 99 100 Asynchronicity of the callbacks is guaranteed. 101 102 @method then 103 @param {Function} [callback] function to execute if the promise 104 resolves successfully 105 @param {Function} [errback] function to execute if the promise 106 resolves unsuccessfully 107 @return {Promise} A promise wrapping the resolution of either "resolve" or 108 "reject" callback 109 **/ 110 then: function (callback, errback) { 111 var Constructor = this.constructor, 112 resolver = this._resolver; 113 114 // using this.constructor allows for customized promises to be 115 // returned instead of plain ones 116 return new Constructor(function (resolve, reject) { 117 resolver._addCallbacks( 118 // Check if callbacks are functions. If not, default to 119 // `resolve` and `reject` respectively. 120 // The wrapping of the callbacks is done here and not in 121 // `_addCallbacks` because it is a feature specific to `then`. 122 // If `done` is added to promises it would call `_addCallbacks` 123 // without defaulting to anything and without wrapping 124 typeof callback === 'function' ? 125 Promise._wrap(resolve, reject, callback) : resolve, 126 typeof errback === 'function' ? 127 Promise._wrap(resolve, reject, errback) : reject 128 ); 129 }); 130 }, 131 132 /** 133 A shorthand for `promise.then(undefined, callback)`. 134 135 Returns a new promise and the error callback gets the same treatment as in 136 `then`: errors get caught and turned into rejections, and the return value 137 of the callback becomes the fulfilled value of the returned promise. 138 139 @method catch 140 @param [Function] errback Callback to be called in case this promise is 141 rejected 142 @return {Promise} A new promise modified by the behavior of the error 143 callback 144 **/ 145 'catch': function (errback) { 146 return this.then(undefined, errback); 147 }, 148 149 /** 150 Returns the current status of the operation. Possible results are 151 "pending", "fulfilled", and "rejected". 152 153 @method getStatus 154 @return {String} 155 @deprecated 156 **/ 157 getStatus: function () { 158 return this._resolver.getStatus(); 159 } 160 }); 161 162 /** 163 Wraps the callback in another function to catch exceptions and turn them into 164 rejections. 165 166 @method _wrap 167 @param {Function} resolve Resolving function of the resolver that 168 handles this promise 169 @param {Function} reject Rejection function of the resolver that 170 handles this promise 171 @param {Function} fn Callback to wrap 172 @return {Function} 173 @private 174 **/ 175 Promise._wrap = function (resolve, reject, fn) { 176 // callbacks and errbacks only get one argument 177 return function (valueOrReason) { 178 var result; 179 180 // Promises model exception handling through callbacks 181 // making both synchronous and asynchronous errors behave 182 // the same way 183 try { 184 // Use the argument coming in to the callback/errback from the 185 // resolution of the parent promise. 186 // The function must be called as a normal function, with no 187 // special value for |this|, as per Promises A+ 188 result = fn(valueOrReason); 189 } catch (e) { 190 reject(e); 191 return; 192 } 193 194 resolve(result); 195 }; 196 }; 197 198 /** 199 Checks if an object or value is a promise. This is cross-implementation 200 compatible, so promises returned from other libraries or native components 201 that are compatible with the Promises A+ spec should be recognized by this 202 method. 203 204 @method isPromise 205 @param {Any} obj The object to test 206 @return {Boolean} Whether the object is a promise or not 207 @static 208 **/ 209 Promise.isPromise = function (obj) { 210 var then; 211 // We test promises by structure to be able to identify other 212 // implementations' promises. This is important for cross compatibility and 213 // In particular Y.when which should recognize any kind of promise 214 // Use try...catch when retrieving obj.then. Return false if it throws 215 // See Promises/A+ 1.1 216 try { 217 then = obj.then; 218 } catch (_) {} 219 return typeof then === 'function'; 220 }; 221 222 /** 223 Ensures that a certain value is a promise. If it is not a promise, it wraps it 224 in one. 225 226 This method can be copied or inherited in subclasses. In that case it will 227 check that the value passed to it is an instance of the correct class. 228 This means that `PromiseSubclass.resolve()` will always return instances of 229 `PromiseSubclass`. 230 231 @method resolve 232 @param {Any} Any object that may or may not be a promise 233 @return {Promise} 234 @static 235 **/ 236 Promise.resolve = function (value) { 237 return Promise.isPromise(value) && value.constructor === this ? value : 238 /*jshint newcap: false */ 239 new this(function (resolve) { 240 /*jshint newcap: true */ 241 resolve(value); 242 }); 243 }; 244 245 /** 246 A shorthand for creating a rejected promise. 247 248 @method reject 249 @param {Any} reason Reason for the rejection of this promise. Usually an Error 250 Object 251 @return {Promise} A rejected promise 252 @static 253 **/ 254 Promise.reject = function (reason) { 255 /*jshint newcap: false */ 256 return new this(function (resolve, reject) { 257 /*jshint newcap: true */ 258 reject(reason); 259 }); 260 }; 261 262 /** 263 Returns a promise that is resolved or rejected when all values are resolved or 264 any is rejected. This is useful for waiting for the resolution of multiple 265 promises, such as reading multiple files in Node.js or making multiple XHR 266 requests in the browser. 267 268 @method all 269 @param {Any[]} values An array of any kind of values, promises or not. If a value is not 270 @return [Promise] A promise for an array of all the fulfillment values 271 @static 272 **/ 273 Promise.all = function (values) { 274 var Promise = this; 275 return new Promise(function (resolve, reject) { 276 if (!Lang.isArray(values)) { 277 reject(new TypeError('Promise.all expects an array of values or promises')); 278 return; 279 } 280 281 var remaining = values.length, 282 i = 0, 283 length = values.length, 284 results = []; 285 286 function oneDone(index) { 287 return function (value) { 288 results[index] = value; 289 290 remaining--; 291 292 if (!remaining) { 293 resolve(results); 294 } 295 }; 296 } 297 298 if (length < 1) { 299 return resolve(results); 300 } 301 302 for (; i < length; i++) { 303 Promise.resolve(values[i]).then(oneDone(i), reject); 304 } 305 }); 306 }; 307 308 /** 309 Returns a promise that is resolved or rejected when any of values is either 310 resolved or rejected. Can be used for providing early feedback in the UI 311 while other operations are still pending. 312 313 @method race 314 @param {Any[]} values An array of values or promises 315 @return {Promise} 316 @static 317 **/ 318 Promise.race = function (values) { 319 var Promise = this; 320 return new Promise(function (resolve, reject) { 321 if (!Lang.isArray(values)) { 322 reject(new TypeError('Promise.race expects an array of values or promises')); 323 return; 324 } 325 326 // just go through the list and resolve and reject at the first change 327 // This abuses the fact that calling resolve/reject multiple times 328 // doesn't change the state of the returned promise 329 for (var i = 0, count = values.length; i < count; i++) { 330 Promise.resolve(values[i]).then(resolve, reject); 331 } 332 }); 333 }; 334 335 Y.Promise = Promise; 336 /** 337 Represents an asynchronous operation. Provides a 338 standard API for subscribing to the moment that the operation completes either 339 successfully (`fulfill()`) or unsuccessfully (`reject()`). 340 341 @class Promise.Resolver 342 @constructor 343 @param {Promise} promise The promise instance this resolver will be handling 344 **/ 345 function Resolver(promise) { 346 /** 347 List of success callbacks 348 349 @property _callbacks 350 @type Array 351 @private 352 **/ 353 this._callbacks = []; 354 355 /** 356 List of failure callbacks 357 358 @property _errbacks 359 @type Array 360 @private 361 **/ 362 this._errbacks = []; 363 364 /** 365 The promise for this Resolver. 366 367 @property promise 368 @type Promise 369 @deprecated 370 **/ 371 this.promise = promise; 372 373 /** 374 The status of the operation. This property may take only one of the following 375 values: 'pending', 'fulfilled' or 'rejected'. 376 377 @property _status 378 @type String 379 @default 'pending' 380 @private 381 **/ 382 this._status = 'pending'; 383 384 /** 385 This value that this promise represents. 386 387 @property _result 388 @type Any 389 @private 390 **/ 391 this._result = null; 392 } 393 394 Y.mix(Resolver.prototype, { 395 /** 396 Resolves the promise, signaling successful completion of the 397 represented operation. All "onFulfilled" subscriptions are executed and passed 398 the value provided to this method. After calling `fulfill()`, `reject()` and 399 `notify()` are disabled. 400 401 @method fulfill 402 @param {Any} value Value to pass along to the "onFulfilled" subscribers 403 **/ 404 fulfill: function (value) { 405 if (this._status === 'pending') { 406 this._result = value; 407 this._status = 'fulfilled'; 408 } 409 410 if (this._status === 'fulfilled') { 411 this._notify(this._callbacks, this._result); 412 413 // Reset the callback list so that future calls to fulfill() 414 // won't call the same callbacks again. Promises keep a list 415 // of callbacks, they're not the same as events. In practice, 416 // calls to fulfill() after the first one should not be made by 417 // the user but by then() 418 this._callbacks = []; 419 420 // Once a promise gets fulfilled it can't be rejected, so 421 // there is no point in keeping the list. Remove it to help 422 // garbage collection 423 this._errbacks = null; 424 } 425 }, 426 427 /** 428 Resolves the promise, signaling *un*successful completion of the 429 represented operation. All "onRejected" subscriptions are executed with 430 the value provided to this method. After calling `reject()`, `resolve()` 431 and `notify()` are disabled. 432 433 @method reject 434 @param {Any} value Value to pass along to the "reject" subscribers 435 **/ 436 reject: function (reason) { 437 if (this._status === 'pending') { 438 this._result = reason; 439 this._status = 'rejected'; 440 } 441 442 if (this._status === 'rejected') { 443 this._notify(this._errbacks, this._result); 444 445 // See fulfill() 446 this._callbacks = null; 447 this._errbacks = []; 448 } 449 }, 450 451 /* 452 Given a certain value A passed as a parameter, this method resolves the 453 promise to the value A. 454 455 If A is a promise, `resolve` will cause the resolver to adopt the state of A 456 and once A is resolved, it will resolve the resolver's promise as well. 457 This behavior "flattens" A by calling `then` recursively and essentially 458 disallows promises-for-promises. 459 460 This is the default algorithm used when using the function passed as the 461 first argument to the promise initialization function. This means that 462 the following code returns a promise for the value 'hello world': 463 464 var promise1 = new Y.Promise(function (resolve) { 465 resolve('hello world'); 466 }); 467 var promise2 = new Y.Promise(function (resolve) { 468 resolve(promise1); 469 }); 470 promise2.then(function (value) { 471 assert(value === 'hello world'); // true 472 }); 473 474 @method resolve 475 @param [Any] value A regular JS value or a promise 476 */ 477 resolve: function (value) { 478 var self = this; 479 480 if (Promise.isPromise(value)) { 481 value.then(function (value) { 482 self.resolve(value); 483 }, function (reason) { 484 self.reject(reason); 485 }); 486 } else { 487 this.fulfill(value); 488 } 489 }, 490 491 /** 492 Schedule execution of a callback to either or both of "resolve" and 493 "reject" resolutions for the Resolver. The callbacks 494 are wrapped in a new Resolver and that Resolver's corresponding promise 495 is returned. This allows operation chaining ala 496 `functionA().then(functionB).then(functionC)` where `functionA` returns 497 a promise, and `functionB` and `functionC` _may_ return promises. 498 499 @method then 500 @param {Function} [callback] function to execute if the Resolver 501 resolves successfully 502 @param {Function} [errback] function to execute if the Resolver 503 resolves unsuccessfully 504 @return {Promise} The promise of a new Resolver wrapping the resolution 505 of either "resolve" or "reject" callback 506 @deprecated 507 **/ 508 then: function (callback, errback) { 509 return this.promise.then(callback, errback); 510 }, 511 512 /** 513 Schedule execution of a callback to either or both of "resolve" and 514 "reject" resolutions of this resolver. If the resolver is not pending, 515 the correct callback gets called automatically. 516 517 @method _addCallbacks 518 @param {Function} [callback] function to execute if the Resolver 519 resolves successfully 520 @param {Function} [errback] function to execute if the Resolver 521 resolves unsuccessfully 522 @private 523 **/ 524 _addCallbacks: function (callback, errback) { 525 var callbackList = this._callbacks, 526 errbackList = this._errbacks, 527 status = this._status, 528 result = this._result; 529 530 if (callbackList && typeof callback === 'function') { 531 callbackList.push(callback); 532 } 533 if (errbackList && typeof errback === 'function') { 534 errbackList.push(errback); 535 } 536 537 // If a promise is already fulfilled or rejected, notify the newly added 538 // callbacks by calling fulfill() or reject() 539 if (status === 'fulfilled') { 540 this.fulfill(result); 541 } else if (status === 'rejected') { 542 this.reject(result); 543 } 544 }, 545 546 /** 547 Returns the current status of the Resolver as a string "pending", 548 "fulfilled", or "rejected". 549 550 @method getStatus 551 @return {String} 552 @deprecated 553 **/ 554 getStatus: function () { 555 return this._status; 556 }, 557 558 /** 559 Executes an array of callbacks from a specified context, passing a set of 560 arguments. 561 562 @method _notify 563 @param {Function[]} subs The array of subscriber callbacks 564 @param {Any} result Value to pass the callbacks 565 @protected 566 **/ 567 _notify: function (subs, result) { 568 // Since callback lists are reset synchronously, the subs list never 569 // changes after _notify() receives it. Avoid calling Y.soon() for 570 // an empty list 571 if (subs.length) { 572 // Calling all callbacks after Y.soon to guarantee 573 // asynchronicity. Because setTimeout can cause unnecessary 574 // delays that *can* become noticeable in some situations 575 // (especially in Node.js) 576 Y.soon(function () { 577 var i, len; 578 579 for (i = 0, len = subs.length; i < len; ++i) { 580 subs[i](result); 581 } 582 }); 583 } 584 } 585 586 }, true); 587 588 Y.Promise.Resolver = Resolver; 589 /** 590 Abstraction API allowing you to interact with promises or raw values as if they 591 were promises. If a non-promise object is passed in, a new Resolver is created 592 and scheduled to resolve asynchronously with the provided value. 593 594 In either case, a promise is returned. If either _callback_ or _errback_ are 595 provided, the promise returned is the one returned from calling 596 `promise.then(callback, errback)` on the provided or created promise. If neither 597 are provided, the original promise is returned. 598 599 @for YUI 600 @method when 601 @param {Any} promise Promise object or value to wrap in a resolved promise 602 @param {Function} [callback] callback to execute if the promise is resolved 603 @param {Function} [errback] callback to execute if the promise is rejected 604 @return {Promise} 605 **/ 606 Y.when = function (promise, callback, errback) { 607 promise = Promise.resolve(promise); 608 609 return (callback || errback) ? promise.then(callback, errback) : promise; 610 }; 611 /** 612 Returns a new promise that will be resolved when all operations have completed. 613 Takes both any numer of values as arguments. If an argument is a not a promise, 614 it will be wrapped in a new promise, same as in `Y.when()`. 615 616 @for YUI 617 @method batch 618 @param {Any} operation* Any number of Y.Promise objects or regular JS values 619 @return {Promise} Promise to be fulfilled when all provided promises are 620 resolved 621 **/ 622 Y.batch = function () { 623 return Promise.all(slice.call(arguments)); 624 }; 625 626 627 }, '3.17.2', {"requires": ["timers"]});
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Thu Aug 11 10:00:09 2016 | Cross-referenced by PHPXref 0.7.1 |