Advertisement
Guest User

when.js 2.2.1 modified to not use AMD

a guest
Jul 18th, 2013
191
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /** @license MIT License (c) copyright 2011-2013 original author or authors */
  2.  
  3. /**
  4.  * A lightweight CommonJS Promises/A and when() implementation
  5.  * when is part of the cujo.js family of libraries (http://cujojs.com/)
  6.  *
  7.  * Licensed under the MIT License at:
  8.  * http://www.opensource.org/licenses/mit-license.php
  9.  *
  10.  * @author Brian Cavalier
  11.  * @author John Hann
  12.  * @version 2.2.1
  13.  */
  14.  
  15.  // MPJ Removed AMD define() code - using simplified code instead
  16.  window.when221 = (function() {
  17.     var global = window;
  18.  
  19.     // Public API
  20.  
  21.     when.promise   = promise;    // Create a pending promise
  22.     when.resolve   = resolve;    // Create a resolved promise
  23.     when.reject    = reject;     // Create a rejected promise
  24.     when.defer     = defer;      // Create a {promise, resolver} pair
  25.  
  26.     when.join      = join;       // Join 2 or more promises
  27.  
  28.     when.all       = all;        // Resolve a list of promises
  29.     when.map       = map;        // Array.map() for promises
  30.     when.reduce    = reduce;     // Array.reduce() for promises
  31.     when.settle    = settle;     // Settle a list of promises
  32.  
  33.     when.any       = any;        // One-winner race
  34.     when.some      = some;       // Multi-winner race
  35.  
  36.     when.isPromise = isPromise;  // Determine if a thing is a promise
  37.  
  38.  
  39.     /**
  40.      * Register an observer for a promise or immediate value.
  41.      *
  42.      * @param {*} promiseOrValue
  43.      * @param {function?} [onFulfilled] callback to be called when promiseOrValue is
  44.      *   successfully fulfilled.  If promiseOrValue is an immediate value, callback
  45.      *   will be invoked immediately.
  46.      * @param {function?} [onRejected] callback to be called when promiseOrValue is
  47.      *   rejected.
  48.      * @param {function?} [onProgress] callback to be called when progress updates
  49.      *   are issued for promiseOrValue.
  50.      * @returns {Promise} a new {@link Promise} that will complete with the return
  51.      *   value of callback or errback or the completion value of promiseOrValue if
  52.      *   callback and/or errback is not supplied.
  53.      */
  54.     function when(promiseOrValue, onFulfilled, onRejected, onProgress) {
  55.         // Get a trusted promise for the input promiseOrValue, and then
  56.         // register promise handlers
  57.         return resolve(promiseOrValue).then(onFulfilled, onRejected, onProgress);
  58.     }
  59.  
  60.     /**
  61.      * Trusted Promise constructor.  A Promise created from this constructor is
  62.      * a trusted when.js promise.  Any other duck-typed promise is considered
  63.      * untrusted.
  64.      * @constructor
  65.      * @name Promise
  66.      */
  67.     function Promise(then, inspect) {
  68.         this.then = then;
  69.         this.inspect = inspect;
  70.     }
  71.  
  72.     Promise.prototype = {
  73.         /**
  74.          * Register a rejection handler.  Shortcut for .then(undefined, onRejected)
  75.          * @param {function?} onRejected
  76.          * @return {Promise}
  77.          */
  78.         otherwise: function(onRejected) {
  79.             return this.then(undef, onRejected);
  80.         },
  81.  
  82.         /**
  83.          * Ensures that onFulfilledOrRejected will be called regardless of whether
  84.          * this promise is fulfilled or rejected.  onFulfilledOrRejected WILL NOT
  85.          * receive the promises' value or reason.  Any returned value will be disregarded.
  86.          * onFulfilledOrRejected may throw or return a rejected promise to signal
  87.          * an additional error.
  88.          * @param {function} onFulfilledOrRejected handler to be called regardless of
  89.          *  fulfillment or rejection
  90.          * @returns {Promise}
  91.          */
  92.         ensure: function(onFulfilledOrRejected) {
  93.             return this.then(injectHandler, injectHandler)['yield'](this);
  94.  
  95.             function injectHandler() {
  96.                 return resolve(onFulfilledOrRejected());
  97.             }
  98.         },
  99.  
  100.         /**
  101.          * Shortcut for .then(function() { return value; })
  102.          * @param  {*} value
  103.          * @return {Promise} a promise that:
  104.          *  - is fulfilled if value is not a promise, or
  105.          *  - if value is a promise, will fulfill with its value, or reject
  106.          *    with its reason.
  107.          */
  108.         'yield': function(value) {
  109.             return this.then(function() {
  110.                 return value;
  111.             });
  112.         },
  113.  
  114.         /**
  115.          * Assumes that this promise will fulfill with an array, and arranges
  116.          * for the onFulfilled to be called with the array as its argument list
  117.          * i.e. onFulfilled.apply(undefined, array).
  118.          * @param {function} onFulfilled function to receive spread arguments
  119.          * @return {Promise}
  120.          */
  121.         spread: function(onFulfilled) {
  122.             return this.then(function(array) {
  123.                 // array may contain promises, so resolve its contents.
  124.                 return all(array, function(array) {
  125.                     return onFulfilled.apply(undef, array);
  126.                 });
  127.             });
  128.         },
  129.  
  130.         /**
  131.          * Shortcut for .then(onFulfilledOrRejected, onFulfilledOrRejected)
  132.          * @deprecated
  133.          */
  134.         always: function(onFulfilledOrRejected, onProgress) {
  135.             return this.then(onFulfilledOrRejected, onFulfilledOrRejected, onProgress);
  136.         }
  137.     };
  138.  
  139.     /**
  140.      * Returns a resolved promise. The returned promise will be
  141.      *  - fulfilled with promiseOrValue if it is a value, or
  142.      *  - if promiseOrValue is a promise
  143.      *    - fulfilled with promiseOrValue's value after it is fulfilled
  144.      *    - rejected with promiseOrValue's reason after it is rejected
  145.      * @param  {*} value
  146.      * @return {Promise}
  147.      */
  148.     function resolve(value) {
  149.         return promise(function(resolve) {
  150.             resolve(value);
  151.         });
  152.     }
  153.  
  154.     /**
  155.      * Returns a rejected promise for the supplied promiseOrValue.  The returned
  156.      * promise will be rejected with:
  157.      * - promiseOrValue, if it is a value, or
  158.      * - if promiseOrValue is a promise
  159.      *   - promiseOrValue's value after it is fulfilled
  160.      *   - promiseOrValue's reason after it is rejected
  161.      * @param {*} promiseOrValue the rejected value of the returned {@link Promise}
  162.      * @return {Promise} rejected {@link Promise}
  163.      */
  164.     function reject(promiseOrValue) {
  165.         return when(promiseOrValue, rejected);
  166.     }
  167.  
  168.     /**
  169.      * Creates a {promise, resolver} pair, either or both of which
  170.      * may be given out safely to consumers.
  171.      * The resolver has resolve, reject, and progress.  The promise
  172.      * has then plus extended promise API.
  173.      *
  174.      * @return {{
  175.      * promise: Promise,
  176.      * resolve: function:Promise,
  177.      * reject: function:Promise,
  178.      * notify: function:Promise
  179.      * resolver: {
  180.      *  resolve: function:Promise,
  181.      *  reject: function:Promise,
  182.      *  notify: function:Promise
  183.      * }}}
  184.      */
  185.     function defer() {
  186.         var deferred, pending, resolved;
  187.  
  188.         // Optimize object shape
  189.         deferred = {
  190.             promise: undef, resolve: undef, reject: undef, notify: undef,
  191.             resolver: { resolve: undef, reject: undef, notify: undef }
  192.         };
  193.  
  194.         deferred.promise = pending = promise(makeDeferred);
  195.  
  196.         return deferred;
  197.  
  198.         function makeDeferred(resolvePending, rejectPending, notifyPending) {
  199.             deferred.resolve = deferred.resolver.resolve = function(value) {
  200.                 if(resolved) {
  201.                     return resolve(value);
  202.                 }
  203.                 resolved = true;
  204.                 resolvePending(value);
  205.                 return pending;
  206.             };
  207.  
  208.             deferred.reject  = deferred.resolver.reject  = function(reason) {
  209.                 if(resolved) {
  210.                     return resolve(rejected(reason));
  211.                 }
  212.                 resolved = true;
  213.                 rejectPending(reason);
  214.                 return pending;
  215.             };
  216.  
  217.             deferred.notify  = deferred.resolver.notify  = function(update) {
  218.                 notifyPending(update);
  219.                 return update;
  220.             };
  221.         }
  222.     }
  223.  
  224.     /**
  225.      * Creates a new promise whose fate is determined by resolver.
  226.      * @param {function} resolver function(resolve, reject, notify)
  227.      * @returns {Promise} promise whose fate is determine by resolver
  228.      */
  229.     function promise(resolver) {
  230.         return _promise(resolver, monitorApi.PromiseStatus && monitorApi.PromiseStatus());
  231.     }
  232.  
  233.     /**
  234.      * Creates a new promise, linked to parent, whose fate is determined
  235.      * by resolver.
  236.      * @param {function} resolver function(resolve, reject, notify)
  237.      * @param {Promise?} status promise from which the new promise is begotten
  238.      * @returns {Promise} promise whose fate is determine by resolver
  239.      * @private
  240.      */
  241.     function _promise(resolver, status) {
  242.         var self, value, handlers = [];
  243.  
  244.         self = new Promise(then, inspect);
  245.  
  246.         // Call the provider resolver to seal the promise's fate
  247.         try {
  248.             resolver(promiseResolve, promiseReject, promiseNotify);
  249.         } catch(e) {
  250.             promiseReject(e);
  251.         }
  252.  
  253.         // Return the promise
  254.         return self;
  255.  
  256.         /**
  257.          * Register handlers for this promise.
  258.          * @param [onFulfilled] {Function} fulfillment handler
  259.          * @param [onRejected] {Function} rejection handler
  260.          * @param [onProgress] {Function} progress handler
  261.          * @return {Promise} new Promise
  262.          */
  263.         function then(onFulfilled, onRejected, onProgress) {
  264.             var next = _promise(function(resolve, reject, notify) {
  265.                 // if not resolved, push onto handlers, otherwise execute asap
  266.                 // but not in the current stack
  267.                 handlers ? handlers.push(run) : enqueue(function() { run(value); });
  268.  
  269.                 function run(p) {
  270.                     p.then(onFulfilled, onRejected, onProgress)
  271.                         .then(resolve, reject, notify);
  272.                 }
  273.  
  274.             }, status && status.observed());
  275.  
  276.             return next;
  277.         }
  278.  
  279.         function inspect() {
  280.             return value ? value.inspect() : toPendingState();
  281.         }
  282.  
  283.         /**
  284.          * Transition from pre-resolution state to post-resolution state, notifying
  285.          * all listeners of the ultimate fulfillment or rejection
  286.          * @param {*|Promise} val resolution value
  287.          */
  288.         function promiseResolve(val) {
  289.             if(!handlers) {
  290.                 return;
  291.             }
  292.  
  293.             value = coerce(val);
  294.             scheduleHandlers(handlers, value);
  295.             handlers = undef;
  296.  
  297.             if (status) {
  298.                 value.then(
  299.                     function () { status.fulfilled(); },
  300.                     function(r) { status.rejected(r); }
  301.                 );
  302.             }
  303.         }
  304.  
  305.         /**
  306.          * Reject this promise with the supplied reason, which will be used verbatim.
  307.          * @param {*} reason reason for the rejection
  308.          */
  309.         function promiseReject(reason) {
  310.             promiseResolve(rejected(reason));
  311.         }
  312.  
  313.         /**
  314.          * Issue a progress event, notifying all progress listeners
  315.          * @param {*} update progress event payload to pass to all listeners
  316.          */
  317.         function promiseNotify(update) {
  318.             if(handlers) {
  319.                 scheduleHandlers(handlers, progressing(update));
  320.             }
  321.         }
  322.     }
  323.  
  324.     /**
  325.      * Coerces x to a trusted Promise
  326.      *
  327.      * @private
  328.      * @param {*} x thing to coerce
  329.      * @returns {Promise} Guaranteed to return a trusted Promise.  If x
  330.      *   is trusted, returns x, otherwise, returns a new, trusted, already-resolved
  331.      *   Promise whose resolution value is:
  332.      *   * the resolution value of x if it's a foreign promise, or
  333.      *   * x if it's a value
  334.      */
  335.     function coerce(x) {
  336.         if(x instanceof Promise) {
  337.             return x;
  338.         }
  339.  
  340.         if (!(x === Object(x) && 'then' in x)) {
  341.             return fulfilled(x);
  342.         }
  343.  
  344.         return promise(function(resolve, reject, notify) {
  345.             enqueue(function() {
  346.                 try {
  347.                     // We must check and assimilate in the same tick, but not the
  348.                     // current tick, careful only to access promiseOrValue.then once.
  349.                     var untrustedThen = x.then;
  350.  
  351.                     if(typeof untrustedThen === 'function') {
  352.                         fcall(untrustedThen, x, resolve, reject, notify);
  353.                     } else {
  354.                         // It's a value, create a fulfilled wrapper
  355.                         resolve(fulfilled(x));
  356.                     }
  357.  
  358.                 } catch(e) {
  359.                     // Something went wrong, reject
  360.                     reject(e);
  361.                 }
  362.             });
  363.         });
  364.     }
  365.  
  366.     /**
  367.      * Create an already-fulfilled promise for the supplied value
  368.      * @private
  369.      * @param {*} value
  370.      * @return {Promise} fulfilled promise
  371.      */
  372.     function fulfilled(value) {
  373.         var self = new Promise(function (onFulfilled) {
  374.             try {
  375.                 return typeof onFulfilled == 'function'
  376.                     ? coerce(onFulfilled(value)) : self;
  377.             } catch (e) {
  378.                 return rejected(e);
  379.             }
  380.         }, function() {
  381.             return toFulfilledState(value);
  382.         });
  383.  
  384.         return self;
  385.     }
  386.  
  387.     /**
  388.      * Create an already-rejected promise with the supplied rejection reason.
  389.      * @private
  390.      * @param {*} reason
  391.      * @return {Promise} rejected promise
  392.      */
  393.     function rejected(reason) {
  394.         var self = new Promise(function (_, onRejected) {
  395.             try {
  396.                 return typeof onRejected == 'function'
  397.                     ? coerce(onRejected(reason)) : self;
  398.             } catch (e) {
  399.                 return rejected(e);
  400.             }
  401.         }, function() {
  402.             return toRejectedState(reason);
  403.         });
  404.  
  405.         return self;
  406.     }
  407.  
  408.     /**
  409.      * Create a progress promise with the supplied update.
  410.      * @private
  411.      * @param {*} update
  412.      * @return {Promise} progress promise
  413.      */
  414.     function progressing(update) {
  415.         var self = new Promise(function (_, __, onProgress) {
  416.             try {
  417.                 return typeof onProgress == 'function'
  418.                     ? progressing(onProgress(update)) : self;
  419.             } catch (e) {
  420.                 return progressing(e);
  421.             }
  422.         });
  423.  
  424.         return self;
  425.     }
  426.  
  427.     /**
  428.      * Schedule a task that will process a list of handlers
  429.      * in the next queue drain run.
  430.      * @private
  431.      * @param {Array} handlers queue of handlers to execute
  432.      * @param {*} value passed as the only arg to each handler
  433.      */
  434.     function scheduleHandlers(handlers, value) {
  435.         enqueue(function() {
  436.             var handler, i = 0;
  437.             while (handler = handlers[i++]) {
  438.                 handler(value);
  439.             }
  440.         });
  441.     }
  442.  
  443.     /**
  444.      * Determines if promiseOrValue is a promise or not
  445.      *
  446.      * @param {*} promiseOrValue anything
  447.      * @returns {boolean} true if promiseOrValue is a {@link Promise}
  448.      */
  449.     function isPromise(promiseOrValue) {
  450.         return promiseOrValue && typeof promiseOrValue.then === 'function';
  451.     }
  452.  
  453.     /**
  454.      * Initiates a competitive race, returning a promise that will resolve when
  455.      * howMany of the supplied promisesOrValues have resolved, or will reject when
  456.      * it becomes impossible for howMany to resolve, for example, when
  457.      * (promisesOrValues.length - howMany) + 1 input promises reject.
  458.      *
  459.      * @param {Array} promisesOrValues array of anything, may contain a mix
  460.      *      of promises and values
  461.      * @param howMany {number} number of promisesOrValues to resolve
  462.      * @param {function?} [onFulfilled] DEPRECATED, use returnedPromise.then()
  463.      * @param {function?} [onRejected] DEPRECATED, use returnedPromise.then()
  464.      * @param {function?} [onProgress] DEPRECATED, use returnedPromise.then()
  465.      * @returns {Promise} promise that will resolve to an array of howMany values that
  466.      *  resolved first, or will reject with an array of
  467.      *  (promisesOrValues.length - howMany) + 1 rejection reasons.
  468.      */
  469.     function some(promisesOrValues, howMany, onFulfilled, onRejected, onProgress) {
  470.  
  471.         return when(promisesOrValues, function(promisesOrValues) {
  472.  
  473.             return promise(resolveSome).then(onFulfilled, onRejected, onProgress);
  474.  
  475.             function resolveSome(resolve, reject, notify) {
  476.                 var toResolve, toReject, values, reasons, fulfillOne, rejectOne, len, i;
  477.  
  478.                 len = promisesOrValues.length >>> 0;
  479.  
  480.                 toResolve = Math.max(0, Math.min(howMany, len));
  481.                 values = [];
  482.  
  483.                 toReject = (len - toResolve) + 1;
  484.                 reasons = [];
  485.  
  486.                 // No items in the input, resolve immediately
  487.                 if (!toResolve) {
  488.                     resolve(values);
  489.  
  490.                 } else {
  491.                     rejectOne = function(reason) {
  492.                         reasons.push(reason);
  493.                         if(!--toReject) {
  494.                             fulfillOne = rejectOne = identity;
  495.                             reject(reasons);
  496.                         }
  497.                     };
  498.  
  499.                     fulfillOne = function(val) {
  500.                         // This orders the values based on promise resolution order
  501.                         values.push(val);
  502.                         if (!--toResolve) {
  503.                             fulfillOne = rejectOne = identity;
  504.                             resolve(values);
  505.                         }
  506.                     };
  507.  
  508.                     for(i = 0; i < len; ++i) {
  509.                         if(i in promisesOrValues) {
  510.                             when(promisesOrValues[i], fulfiller, rejecter, notify);
  511.                         }
  512.                     }
  513.                 }
  514.  
  515.                 function rejecter(reason) {
  516.                     rejectOne(reason);
  517.                 }
  518.  
  519.                 function fulfiller(val) {
  520.                     fulfillOne(val);
  521.                 }
  522.             }
  523.         });
  524.     }
  525.  
  526.     /**
  527.      * Initiates a competitive race, returning a promise that will resolve when
  528.      * any one of the supplied promisesOrValues has resolved or will reject when
  529.      * *all* promisesOrValues have rejected.
  530.      *
  531.      * @param {Array|Promise} promisesOrValues array of anything, may contain a mix
  532.      *      of {@link Promise}s and values
  533.      * @param {function?} [onFulfilled] DEPRECATED, use returnedPromise.then()
  534.      * @param {function?} [onRejected] DEPRECATED, use returnedPromise.then()
  535.      * @param {function?} [onProgress] DEPRECATED, use returnedPromise.then()
  536.      * @returns {Promise} promise that will resolve to the value that resolved first, or
  537.      * will reject with an array of all rejected inputs.
  538.      */
  539.     function any(promisesOrValues, onFulfilled, onRejected, onProgress) {
  540.  
  541.         function unwrapSingleResult(val) {
  542.             return onFulfilled ? onFulfilled(val[0]) : val[0];
  543.         }
  544.  
  545.         return some(promisesOrValues, 1, unwrapSingleResult, onRejected, onProgress);
  546.     }
  547.  
  548.     /**
  549.      * Return a promise that will resolve only once all the supplied promisesOrValues
  550.      * have resolved. The resolution value of the returned promise will be an array
  551.      * containing the resolution values of each of the promisesOrValues.
  552.      * @memberOf when
  553.      *
  554.      * @param {Array|Promise} promisesOrValues array of anything, may contain a mix
  555.      *      of {@link Promise}s and values
  556.      * @param {function?} [onFulfilled] DEPRECATED, use returnedPromise.then()
  557.      * @param {function?} [onRejected] DEPRECATED, use returnedPromise.then()
  558.      * @param {function?} [onProgress] DEPRECATED, use returnedPromise.then()
  559.      * @returns {Promise}
  560.      */
  561.     function all(promisesOrValues, onFulfilled, onRejected, onProgress) {
  562.         return _map(promisesOrValues, identity).then(onFulfilled, onRejected, onProgress);
  563.     }
  564.  
  565.     /**
  566.      * Joins multiple promises into a single returned promise.
  567.      * @return {Promise} a promise that will fulfill when *all* the input promises
  568.      * have fulfilled, or will reject when *any one* of the input promises rejects.
  569.      */
  570.     function join(/* ...promises */) {
  571.         return _map(arguments, identity);
  572.     }
  573.  
  574.     /**
  575.      * Settles all input promises such that they are guaranteed not to
  576.      * be pending once the returned promise fulfills. The returned promise
  577.      * will always fulfill, except in the case where `array` is a promise
  578.      * that rejects.
  579.      * @param {Array|Promise} array or promise for array of promises to settle
  580.      * @returns {Promise} promise that always fulfills with an array of
  581.      *  outcome snapshots for each input promise.
  582.      */
  583.     function settle(array) {
  584.         return _map(array, toFulfilledState, toRejectedState);
  585.     }
  586.  
  587.     /**
  588.      * Promise-aware array map function, similar to `Array.prototype.map()`,
  589.      * but input array may contain promises or values.
  590.      * @param {Array|Promise} array array of anything, may contain promises and values
  591.      * @param {function} mapFunc map function which may return a promise or value
  592.      * @returns {Promise} promise that will fulfill with an array of mapped values
  593.      *  or reject if any input promise rejects.
  594.      */
  595.     function map(array, mapFunc) {
  596.         return _map(array, mapFunc);
  597.     }
  598.  
  599.     /**
  600.      * Internal map that allows a fallback to handle rejections
  601.      * @param {Array|Promise} array array of anything, may contain promises and values
  602.      * @param {function} mapFunc map function which may return a promise or value
  603.      * @param {function?} fallback function to handle rejected promises
  604.      * @returns {Promise} promise that will fulfill with an array of mapped values
  605.      *  or reject if any input promise rejects.
  606.      */
  607.     function _map(array, mapFunc, fallback) {
  608.         return when(array, function(array) {
  609.  
  610.             return promise(resolveMap);
  611.  
  612.             function resolveMap(resolve, reject, notify) {
  613.                 var results, len, toResolve, i;
  614.  
  615.                 // Since we know the resulting length, we can preallocate the results
  616.                 // array to avoid array expansions.
  617.                 toResolve = len = array.length >>> 0;
  618.                 results = [];
  619.  
  620.                 if(!toResolve) {
  621.                     resolve(results);
  622.                     return;
  623.                 }
  624.  
  625.                 // Since mapFunc may be async, get all invocations of it into flight
  626.                 for(i = 0; i < len; i++) {
  627.                     if(i in array) {
  628.                         resolveOne(array[i], i);
  629.                     } else {
  630.                         --toResolve;
  631.                     }
  632.                 }
  633.  
  634.                 function resolveOne(item, i) {
  635.                     when(item, mapFunc, fallback).then(function(mapped) {
  636.                         results[i] = mapped;
  637.  
  638.                         if(!--toResolve) {
  639.                             resolve(results);
  640.                         }
  641.                     }, reject, notify);
  642.                 }
  643.             }
  644.         });
  645.     }
  646.  
  647.     /**
  648.      * Traditional reduce function, similar to `Array.prototype.reduce()`, but
  649.      * input may contain promises and/or values, and reduceFunc
  650.      * may return either a value or a promise, *and* initialValue may
  651.      * be a promise for the starting value.
  652.      *
  653.      * @param {Array|Promise} promise array or promise for an array of anything,
  654.      *      may contain a mix of promises and values.
  655.      * @param {function} reduceFunc reduce function reduce(currentValue, nextValue, index, total),
  656.      *      where total is the total number of items being reduced, and will be the same
  657.      *      in each call to reduceFunc.
  658.      * @returns {Promise} that will resolve to the final reduced value
  659.      */
  660.     function reduce(promise, reduceFunc /*, initialValue */) {
  661.         var args = fcall(slice, arguments, 1);
  662.  
  663.         return when(promise, function(array) {
  664.             var total;
  665.  
  666.             total = array.length;
  667.  
  668.             // Wrap the supplied reduceFunc with one that handles promises and then
  669.             // delegates to the supplied.
  670.             args[0] = function (current, val, i) {
  671.                 return when(current, function (c) {
  672.                     return when(val, function (value) {
  673.                         return reduceFunc(c, value, i, total);
  674.                     });
  675.                 });
  676.             };
  677.  
  678.             return reduceArray.apply(array, args);
  679.         });
  680.     }
  681.  
  682.     // Snapshot states
  683.  
  684.     /**
  685.      * Creates a fulfilled state snapshot
  686.      * @private
  687.      * @param {*} x any value
  688.      * @returns {{state:'fulfilled',value:*}}
  689.      */
  690.     function toFulfilledState(x) {
  691.         return { state: 'fulfilled', value: x };
  692.     }
  693.  
  694.     /**
  695.      * Creates a rejected state snapshot
  696.      * @private
  697.      * @param {*} x any reason
  698.      * @returns {{state:'rejected',reason:*}}
  699.      */
  700.     function toRejectedState(x) {
  701.         return { state: 'rejected', reason: x };
  702.     }
  703.  
  704.     /**
  705.      * Creates a pending state snapshot
  706.      * @private
  707.      * @returns {{state:'pending'}}
  708.      */
  709.     function toPendingState() {
  710.         return { state: 'pending' };
  711.     }
  712.  
  713.     //
  714.     // Utilities, etc.
  715.     //
  716.  
  717.     var reduceArray, slice, fcall, nextTick, handlerQueue,
  718.         setTimeout, funcProto, call, arrayProto, monitorApi, undef;
  719.  
  720.     //
  721.     // Shared handler queue processing
  722.     //
  723.     // Credit to Twisol (https://github.com/Twisol) for suggesting
  724.     // this type of extensible queue + trampoline approach for
  725.     // next-tick conflation.
  726.  
  727.     handlerQueue = [];
  728.  
  729.     /**
  730.      * Enqueue a task. If the queue is not currently scheduled to be
  731.      * drained, schedule it.
  732.      * @param {function} task
  733.      */
  734.     function enqueue(task) {
  735.         if(handlerQueue.push(task) === 1) {
  736.             nextTick(drainQueue);
  737.         }
  738.     }
  739.  
  740.     /**
  741.      * Drain the handler queue entirely, being careful to allow the
  742.      * queue to be extended while it is being processed, and to continue
  743.      * processing until it is truly empty.
  744.      */
  745.     function drainQueue() {
  746.         var task, i = 0;
  747.  
  748.         while(task = handlerQueue[i++]) {
  749.             task();
  750.         }
  751.  
  752.         handlerQueue = [];
  753.     }
  754.  
  755.     //
  756.     // Capture function and array utils
  757.     //
  758.     /*global setImmediate,process,vertx*/
  759.  
  760.     // Allow attaching the monitor to when() if env has no console
  761.     monitorApi = typeof console != 'undefined' ? console : when;
  762.  
  763.     // capture setTimeout to avoid being caught by fake timers used in time based tests
  764.     setTimeout = global.setTimeout;
  765.     // Prefer setImmediate, cascade to node, vertx and finally setTimeout
  766.     nextTick = typeof setImmediate === 'function' ? setImmediate.bind(global)
  767.         : typeof process === 'object' && process.nextTick ? process.nextTick
  768.         : typeof vertx === 'object' ? vertx.runOnLoop // vert.x
  769.             : function(task) { setTimeout(task, 0); }; // fallback
  770.  
  771.     // Safe function calls
  772.     funcProto = Function.prototype;
  773.     call = funcProto.call;
  774.     fcall = funcProto.bind
  775.         ? call.bind(call)
  776.         : function(f, context) {
  777.             return f.apply(context, slice.call(arguments, 2));
  778.         };
  779.  
  780.     // Safe array ops
  781.     arrayProto = [];
  782.     slice = arrayProto.slice;
  783.  
  784.     // ES5 reduce implementation if native not available
  785.     // See: http://es5.github.com/#x15.4.4.21 as there are many
  786.     // specifics and edge cases.  ES5 dictates that reduce.length === 1
  787.     // This implementation deviates from ES5 spec in the following ways:
  788.     // 1. It does not check if reduceFunc is a Callable
  789.     reduceArray = arrayProto.reduce ||
  790.         function(reduceFunc /*, initialValue */) {
  791.             /*jshint maxcomplexity: 7*/
  792.             var arr, args, reduced, len, i;
  793.  
  794.             i = 0;
  795.             arr = Object(this);
  796.             len = arr.length >>> 0;
  797.             args = arguments;
  798.  
  799.             // If no initialValue, use first item of array (we know length !== 0 here)
  800.             // and adjust i to start at second item
  801.             if(args.length <= 1) {
  802.                 // Skip to the first real element in the array
  803.                 for(;;) {
  804.                     if(i in arr) {
  805.                         reduced = arr[i++];
  806.                         break;
  807.                     }
  808.  
  809.                     // If we reached the end of the array without finding any real
  810.                     // elements, it's a TypeError
  811.                     if(++i >= len) {
  812.                         throw new TypeError();
  813.                     }
  814.                 }
  815.             } else {
  816.                 // If initialValue provided, use it
  817.                 reduced = args[1];
  818.             }
  819.  
  820.             // Do the actual reduce
  821.             for(;i < len; ++i) {
  822.                 if(i in arr) {
  823.                     reduced = reduceFunc(reduced, arr[i], i, arr);
  824.                 }
  825.             }
  826.  
  827.             return reduced;
  828.         };
  829.  
  830.     function identity(x) {
  831.         return x;
  832.     }
  833.  
  834.     return when;
  835. })();
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement