src/cm/media/js/lib/yui/yui_3.10.3/build/promise/promise-debug.js
changeset 525 89ef5ed3c48b
equal deleted inserted replaced
524:322d0feea350 525:89ef5ed3c48b
       
     1 /*
       
     2 YUI 3.10.3 (build 2fb5187)
       
     3 Copyright 2013 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 `fulfill()`
       
    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 /**
       
    37 A promise represents a value that may not yet be available. Promises allow
       
    38 you to chain asynchronous operations, write synchronous looking code and
       
    39 handle errors throughout the process.
       
    40 
       
    41 This constructor takes a function as a parameter where you can insert the logic
       
    42 that fulfills or rejects this promise. The fulfillment value and the rejection
       
    43 reason can be any JavaScript value. It's encouraged that rejection reasons be
       
    44 error objects
       
    45 
       
    46 <pre><code>
       
    47 var fulfilled = new Y.Promise(function (fulfill) {
       
    48     fulfill('I am a fulfilled promise');
       
    49 });
       
    50 
       
    51 var rejected = new Y.Promise(function (fulfill, reject) {
       
    52     reject(new Error('I am a rejected promise'));
       
    53 });
       
    54 </code></pre>
       
    55 
       
    56 @class Promise
       
    57 @constructor
       
    58 @param {Function} fn A function where to insert the logic that resolves this
       
    59         promise. Receives `fulfill` and `reject` functions as parameters.
       
    60         This function is called synchronously.
       
    61 **/
       
    62 function Promise(fn) {
       
    63     if (!(this instanceof Promise)) {
       
    64         return new Promise(fn);
       
    65     }
       
    66 
       
    67     var resolver = new Promise.Resolver(this);
       
    68 
       
    69     /**
       
    70     A reference to the resolver object that handles this promise
       
    71     
       
    72     @property _resolver
       
    73     @type Object
       
    74     @private
       
    75     */
       
    76     this._resolver = resolver;
       
    77 
       
    78     fn.call(this, function (value) {
       
    79         resolver.fulfill(value);
       
    80     }, function (reason) {
       
    81         resolver.reject(reason);
       
    82     });
       
    83 }
       
    84 
       
    85 Y.mix(Promise.prototype, {
       
    86     /**
       
    87     Schedule execution of a callback to either or both of "fulfill" and
       
    88     "reject" resolutions for this promise. The callbacks are wrapped in a new
       
    89     promise and that promise is returned.  This allows operation chaining ala
       
    90     `functionA().then(functionB).then(functionC)` where `functionA` returns
       
    91     a promise, and `functionB` and `functionC` _may_ return promises.
       
    92 
       
    93     Asynchronicity of the callbacks is guaranteed.
       
    94 
       
    95     @method then
       
    96     @param {Function} [callback] function to execute if the promise
       
    97                 resolves successfully
       
    98     @param {Function} [errback] function to execute if the promise
       
    99                 resolves unsuccessfully
       
   100     @return {Promise} A promise wrapping the resolution of either "resolve" or
       
   101                 "reject" callback
       
   102     **/
       
   103     then: function (callback, errback) {
       
   104         return this._resolver.then(callback, errback);
       
   105     },
       
   106 
       
   107     /**
       
   108     Returns the current status of the operation. Possible results are
       
   109     "pending", "fulfilled", and "rejected".
       
   110 
       
   111     @method getStatus
       
   112     @return {String}
       
   113     **/
       
   114     getStatus: function () {
       
   115         return this._resolver.getStatus();
       
   116     }
       
   117 });
       
   118 
       
   119 /**
       
   120 Checks if an object or value is a promise. This is cross-implementation
       
   121 compatible, so promises returned from other libraries or native components
       
   122 that are compatible with the Promises A+ spec should be recognized by this
       
   123 method.
       
   124 
       
   125 @method isPromise
       
   126 @param {Any} obj The object to test
       
   127 @return {Boolean} Whether the object is a promise or not
       
   128 @static
       
   129 **/
       
   130 Promise.isPromise = function (obj) {
       
   131     // We test promises by form to be able to identify other implementations
       
   132     // as promises. This is important for cross compatibility and in particular
       
   133     // Y.when which should take any kind of promise
       
   134     return !!obj && typeof obj.then === 'function';
       
   135 };
       
   136 
       
   137 Y.Promise = Promise;
       
   138 /**
       
   139 Represents an asynchronous operation. Provides a
       
   140 standard API for subscribing to the moment that the operation completes either
       
   141 successfully (`fulfill()`) or unsuccessfully (`reject()`).
       
   142 
       
   143 @class Promise.Resolver
       
   144 @constructor
       
   145 @param {Promise} promise The promise instance this resolver will be handling
       
   146 **/
       
   147 function Resolver(promise) {
       
   148     /**
       
   149     List of success callbacks
       
   150 
       
   151     @property _callbacks
       
   152     @type Array
       
   153     @private
       
   154     **/
       
   155     this._callbacks = [];
       
   156 
       
   157     /**
       
   158     List of failure callbacks
       
   159 
       
   160     @property _errbacks
       
   161     @type Array
       
   162     @private
       
   163     **/
       
   164     this._errbacks = [];
       
   165 
       
   166     /**
       
   167     The promise for this Resolver.
       
   168 
       
   169     @property promise
       
   170     @type Promise
       
   171     **/
       
   172     this.promise = promise;
       
   173 
       
   174     /**
       
   175     The status of the operation. This property may take only one of the following
       
   176     values: 'pending', 'fulfilled' or 'rejected'.
       
   177 
       
   178     @property _status
       
   179     @type String
       
   180     @default 'pending'
       
   181     @private
       
   182     **/
       
   183     this._status = 'pending';
       
   184 }
       
   185 
       
   186 Y.mix(Resolver.prototype, {
       
   187     /**
       
   188     Resolves the promise, signaling successful completion of the
       
   189     represented operation. All "onFulfilled" subscriptions are executed and passed
       
   190     the value provided to this method. After calling `fulfill()`, `reject()` and
       
   191     `notify()` are disabled.
       
   192 
       
   193     @method fulfill
       
   194     @param {Any} value Value to pass along to the "onFulfilled" subscribers
       
   195     **/
       
   196     fulfill: function (value) {
       
   197         if (this._status === 'pending') {
       
   198             this._result = value;
       
   199         }
       
   200 
       
   201         if (this._status !== 'rejected') {
       
   202             this._notify(this._callbacks, this._result);
       
   203 
       
   204             // Reset the callback list so that future calls to fulfill()
       
   205             // won't call the same callbacks again. Promises keep a list
       
   206             // of callbacks, they're not the same as events. In practice,
       
   207             // calls to fulfill() after the first one should not be made by
       
   208             // the user but by then()
       
   209             this._callbacks = [];
       
   210 
       
   211             // Once a promise gets fulfilled it can't be rejected, so
       
   212             // there is no point in keeping the list. Remove it to help
       
   213             // garbage collection
       
   214             this._errbacks = null;
       
   215 
       
   216             this._status = 'fulfilled';
       
   217         }
       
   218     },
       
   219 
       
   220     /**
       
   221     Resolves the promise, signaling *un*successful completion of the
       
   222     represented operation. All "onRejected" subscriptions are executed with
       
   223     the value provided to this method. After calling `reject()`, `resolve()`
       
   224     and `notify()` are disabled.
       
   225 
       
   226     @method reject
       
   227     @param {Any} value Value to pass along to the "reject" subscribers
       
   228     **/
       
   229     reject: function (reason) {
       
   230         if (this._status === 'pending') {
       
   231             this._result = reason;
       
   232         }
       
   233 
       
   234         if (this._status !== 'fulfilled') {
       
   235             this._notify(this._errbacks, this._result);
       
   236 
       
   237             // See fulfill()
       
   238             this._callbacks = null;
       
   239             this._errbacks = [];
       
   240 
       
   241             this._status = 'rejected';
       
   242         }
       
   243     },
       
   244 
       
   245     /**
       
   246     Schedule execution of a callback to either or both of "resolve" and
       
   247     "reject" resolutions for the Resolver.  The callbacks
       
   248     are wrapped in a new Resolver and that Resolver's corresponding promise
       
   249     is returned.  This allows operation chaining ala
       
   250     `functionA().then(functionB).then(functionC)` where `functionA` returns
       
   251     a promise, and `functionB` and `functionC` _may_ return promises.
       
   252 
       
   253     @method then
       
   254     @param {Function} [callback] function to execute if the Resolver
       
   255                 resolves successfully
       
   256     @param {Function} [errback] function to execute if the Resolver
       
   257                 resolves unsuccessfully
       
   258     @return {Promise} The promise of a new Resolver wrapping the resolution
       
   259                 of either "resolve" or "reject" callback
       
   260     **/
       
   261     then: function (callback, errback) {
       
   262         // When the current promise is fulfilled or rejected, either the
       
   263         // callback or errback will be executed via the function pushed onto
       
   264         // this._callbacks or this._errbacks.  However, to allow then()
       
   265         // chaining, the execution of either function needs to be represented
       
   266         // by a Resolver (the same Resolver can represent both flow paths), and
       
   267         // its promise returned.
       
   268         var promise = this.promise,
       
   269             thenFulfill, thenReject,
       
   270 
       
   271             // using promise constructor allows for customized promises to be
       
   272             // returned instead of plain ones
       
   273             then = new promise.constructor(function (fulfill, reject) {
       
   274                 thenFulfill = fulfill;
       
   275                 thenReject = reject;
       
   276             }),
       
   277 
       
   278             callbackList = this._callbacks || [],
       
   279             errbackList  = this._errbacks  || [];
       
   280 
       
   281         // Because the callback and errback are represented by a Resolver, it
       
   282         // must be fulfilled or rejected to propagate through the then() chain.
       
   283         // The same logic applies to resolve() and reject() for fulfillment.
       
   284         callbackList.push(typeof callback === 'function' ?
       
   285             this._wrap(thenFulfill, thenReject, callback) : thenFulfill);
       
   286         errbackList.push(typeof errback === 'function' ?
       
   287             this._wrap(thenFulfill, thenReject, errback) : thenReject);
       
   288 
       
   289         // If a promise is already fulfilled or rejected, notify the newly added
       
   290         // callbacks by calling fulfill() or reject()
       
   291         if (this._status === 'fulfilled') {
       
   292             this.fulfill(this._result);
       
   293         } else if (this._status === 'rejected') {
       
   294             this.reject(this._result);
       
   295         }
       
   296 
       
   297         return then;
       
   298     },
       
   299 
       
   300     /**
       
   301     Wraps the callback in Y.soon to guarantee its asynchronous execution. It
       
   302     also catches exceptions to turn them into rejections and links promises
       
   303     returned from the `then` callback.
       
   304 
       
   305     @method _wrap
       
   306     @param {Function} thenFulfill Fulfillment function of the resolver that
       
   307                         handles this promise
       
   308     @param {Function} thenReject Rejection function of the resolver that
       
   309                         handles this promise
       
   310     @param {Function} fn Callback to wrap
       
   311     @return {Function}
       
   312     @private
       
   313     **/
       
   314     _wrap: function (thenFulfill, thenReject, fn) {
       
   315         var promise = this.promise;
       
   316 
       
   317         return function () {
       
   318             // The args coming in to the callback/errback from the
       
   319             // resolution of the parent promise.
       
   320             var args = arguments;
       
   321 
       
   322             // Wrapping all callbacks in Y.soon to guarantee
       
   323             // asynchronicity. Because setTimeout can cause unnecessary
       
   324             // delays that *can* become noticeable in some situations
       
   325             // (especially in Node.js)
       
   326             Y.soon(function () {
       
   327                 // Call the callback/errback with promise as `this` to
       
   328                 // preserve the contract that access to the deferred is
       
   329                 // only for code that may resolve/reject it.
       
   330                 // Another option would be call the function from the
       
   331                 // global context, but it seemed less useful.
       
   332                 var result;
       
   333 
       
   334                 // Promises model exception handling through callbacks
       
   335                 // making both synchronous and asynchronous errors behave
       
   336                 // the same way
       
   337                 try {
       
   338                     result = fn.apply(promise, args);
       
   339                 } catch (e) {
       
   340                     return thenReject(e);
       
   341                 }
       
   342 
       
   343                 if (Promise.isPromise(result)) {
       
   344                     // Returning a promise from a callback makes the current
       
   345                     // promise sync up with the returned promise
       
   346                     result.then(thenFulfill, thenReject);
       
   347                 } else {
       
   348                     // Non-promise return values always trigger resolve()
       
   349                     // because callback is affirmative, and errback is
       
   350                     // recovery.  To continue on the rejection path, errbacks
       
   351                     // must return rejected promises or throw.
       
   352                     thenFulfill(result);
       
   353                 }
       
   354             });
       
   355         };
       
   356     },
       
   357 
       
   358     /**
       
   359     Returns the current status of the Resolver as a string "pending",
       
   360     "fulfilled", or "rejected".
       
   361 
       
   362     @method getStatus
       
   363     @return {String}
       
   364     **/
       
   365     getStatus: function () {
       
   366         return this._status;
       
   367     },
       
   368 
       
   369     /**
       
   370     Executes an array of callbacks from a specified context, passing a set of
       
   371     arguments.
       
   372 
       
   373     @method _notify
       
   374     @param {Function[]} subs The array of subscriber callbacks
       
   375     @param {Any} result Value to pass the callbacks
       
   376     @protected
       
   377     **/
       
   378     _notify: function (subs, result) {
       
   379         var i, len;
       
   380 
       
   381         for (i = 0, len = subs.length; i < len; ++i) {
       
   382             subs[i](result);
       
   383         }
       
   384     }
       
   385 
       
   386 }, true);
       
   387 
       
   388 Y.Promise.Resolver = Resolver;
       
   389 /**
       
   390 Abstraction API allowing you to interact with promises or raw values as if they
       
   391 were promises. If a non-promise object is passed in, a new Resolver is created
       
   392 and scheduled to resolve asynchronously with the provided value.
       
   393 
       
   394 In either case, a promise is returned.  If either _callback_ or _errback_ are
       
   395 provided, the promise returned is the one returned from calling
       
   396 `promise.then(callback, errback)` on the provided or created promise.  If neither
       
   397 are provided, the original promise is returned.
       
   398 
       
   399 @for YUI
       
   400 @method when
       
   401 @param {Any} promise Promise object or value to wrap in a resolved promise
       
   402 @param {Function} [callback] callback to execute if the promise is resolved
       
   403 @param {Function} [errback] callback to execute if the promise is rejected
       
   404 @return {Promise}
       
   405 **/
       
   406 Y.when = function (promise, callback, errback) {
       
   407     var value;
       
   408 
       
   409     if (!Y.Promise.isPromise(promise)) {
       
   410         value = promise;
       
   411 
       
   412         promise = new Y.Promise(function (fulfill) {
       
   413             fulfill(value);
       
   414         });
       
   415     }
       
   416 
       
   417     return (callback || errback) ? promise.then(callback, errback) : promise;
       
   418 };
       
   419 var slice = [].slice;
       
   420 
       
   421 /**
       
   422 Returns a new promise that will be resolved when all operations have completed.
       
   423 Takes both any numer of values as arguments. If an argument is a not a promise,
       
   424 it will be wrapped in a new promise, same as in `Y.when()`.
       
   425 
       
   426 @for YUI
       
   427 @method batch
       
   428 @param {Any} operation* Any number of Y.Promise objects or regular JS values
       
   429 @return {Promise} Promise to be fulfilled when all provided promises are
       
   430                     resolved
       
   431 **/
       
   432 Y.batch = function () {
       
   433     var funcs     = slice.call(arguments),
       
   434         remaining = funcs.length,
       
   435         i         = 0,
       
   436         length    = funcs.length,
       
   437         results   = [];
       
   438 
       
   439     return new Y.Promise(function (fulfill, reject) {
       
   440         var allDone = this;
       
   441 
       
   442         function oneDone(index) {
       
   443             return function (value) {
       
   444                 results[index] = value;
       
   445 
       
   446                 remaining--;
       
   447 
       
   448                 if (!remaining && allDone.getStatus() !== 'rejected') {
       
   449                     fulfill(results);
       
   450                 }
       
   451             };
       
   452         }
       
   453 
       
   454         if (length < 1) {
       
   455             return fulfill(results);
       
   456         }
       
   457 
       
   458         for (; i < length; i++) {
       
   459             Y.when(funcs[i], oneDone(i), reject);
       
   460         }
       
   461     });
       
   462 };
       
   463 
       
   464 
       
   465 }, '3.10.3', {"requires": ["timers"]});