diff options
Diffstat (limited to 'node_modules/when/lib/decorators/array.js')
| -rw-r--r-- | node_modules/when/lib/decorators/array.js | 285 |
1 files changed, 285 insertions, 0 deletions
diff --git a/node_modules/when/lib/decorators/array.js b/node_modules/when/lib/decorators/array.js new file mode 100644 index 00000000..de0d373f --- /dev/null +++ b/node_modules/when/lib/decorators/array.js @@ -0,0 +1,285 @@ +/** @license MIT License (c) copyright 2010-2014 original author or authors */ +/** @author Brian Cavalier */ +/** @author John Hann */ + +(function(define) { 'use strict'; +define(function(require) { + + var state = require('../state'); + var applier = require('../apply'); + + return function array(Promise) { + + var applyFold = applier(Promise); + var toPromise = Promise.resolve; + var all = Promise.all; + + var ar = Array.prototype.reduce; + var arr = Array.prototype.reduceRight; + var slice = Array.prototype.slice; + + // Additional array combinators + + Promise.any = any; + Promise.some = some; + Promise.settle = settle; + + Promise.map = map; + Promise.filter = filter; + Promise.reduce = reduce; + Promise.reduceRight = reduceRight; + + /** + * When this promise fulfills with an array, do + * onFulfilled.apply(void 0, array) + * @param {function} onFulfilled function to apply + * @returns {Promise} promise for the result of applying onFulfilled + */ + Promise.prototype.spread = function(onFulfilled) { + return this.then(all).then(function(array) { + return onFulfilled.apply(this, array); + }); + }; + + return Promise; + + /** + * One-winner competitive race. + * Return a promise that will fulfill when one of the promises + * in the input array fulfills, or will reject when all promises + * have rejected. + * @param {array} promises + * @returns {Promise} promise for the first fulfilled value + */ + function any(promises) { + var p = Promise._defer(); + var resolver = p._handler; + var l = promises.length>>>0; + + var pending = l; + var errors = []; + + for (var h, x, i = 0; i < l; ++i) { + x = promises[i]; + if(x === void 0 && !(i in promises)) { + --pending; + continue; + } + + h = Promise._handler(x); + if(h.state() > 0) { + resolver.become(h); + Promise._visitRemaining(promises, i, h); + break; + } else { + h.visit(resolver, handleFulfill, handleReject); + } + } + + if(pending === 0) { + resolver.reject(new RangeError('any(): array must not be empty')); + } + + return p; + + function handleFulfill(x) { + /*jshint validthis:true*/ + errors = null; + this.resolve(x); // this === resolver + } + + function handleReject(e) { + /*jshint validthis:true*/ + if(this.resolved) { // this === resolver + return; + } + + errors.push(e); + if(--pending === 0) { + this.reject(errors); + } + } + } + + /** + * N-winner competitive race + * Return a promise that will fulfill when n input promises have + * fulfilled, or will reject when it becomes impossible for n + * input promises to fulfill (ie when promises.length - n + 1 + * have rejected) + * @param {array} promises + * @param {number} n + * @returns {Promise} promise for the earliest n fulfillment values + * + * @deprecated + */ + function some(promises, n) { + /*jshint maxcomplexity:7*/ + var p = Promise._defer(); + var resolver = p._handler; + + var results = []; + var errors = []; + + var l = promises.length>>>0; + var nFulfill = 0; + var nReject; + var x, i; // reused in both for() loops + + // First pass: count actual array items + for(i=0; i<l; ++i) { + x = promises[i]; + if(x === void 0 && !(i in promises)) { + continue; + } + ++nFulfill; + } + + // Compute actual goals + n = Math.max(n, 0); + nReject = (nFulfill - n + 1); + nFulfill = Math.min(n, nFulfill); + + if(n > nFulfill) { + resolver.reject(new RangeError('some(): array must contain at least ' + + n + ' item(s), but had ' + nFulfill)); + } else if(nFulfill === 0) { + resolver.resolve(results); + } + + // Second pass: observe each array item, make progress toward goals + for(i=0; i<l; ++i) { + x = promises[i]; + if(x === void 0 && !(i in promises)) { + continue; + } + + Promise._handler(x).visit(resolver, fulfill, reject, resolver.notify); + } + + return p; + + function fulfill(x) { + /*jshint validthis:true*/ + if(this.resolved) { // this === resolver + return; + } + + results.push(x); + if(--nFulfill === 0) { + errors = null; + this.resolve(results); + } + } + + function reject(e) { + /*jshint validthis:true*/ + if(this.resolved) { // this === resolver + return; + } + + errors.push(e); + if(--nReject === 0) { + results = null; + this.reject(errors); + } + } + } + + /** + * Apply f to the value of each promise in a list of promises + * and return a new list containing the results. + * @param {array} promises + * @param {function(x:*, index:Number):*} f mapping function + * @returns {Promise} + */ + function map(promises, f) { + return Promise._traverse(f, promises); + } + + /** + * Filter the provided array of promises using the provided predicate. Input may + * contain promises and values + * @param {Array} promises array of promises and values + * @param {function(x:*, index:Number):boolean} predicate filtering predicate. + * Must return truthy (or promise for truthy) for items to retain. + * @returns {Promise} promise that will fulfill with an array containing all items + * for which predicate returned truthy. + */ + function filter(promises, predicate) { + var a = slice.call(promises); + return Promise._traverse(predicate, a).then(function(keep) { + return filterSync(a, keep); + }); + } + + function filterSync(promises, keep) { + // Safe because we know all promises have fulfilled if we've made it this far + var l = keep.length; + var filtered = new Array(l); + for(var i=0, j=0; i<l; ++i) { + if(keep[i]) { + filtered[j++] = Promise._handler(promises[i]).value; + } + } + filtered.length = j; + return filtered; + + } + + /** + * Return a promise that will always fulfill with an array containing + * the outcome states of all input promises. The returned promise + * will never reject. + * @param {Array} promises + * @returns {Promise} promise for array of settled state descriptors + */ + function settle(promises) { + return all(promises.map(settleOne)); + } + + function settleOne(p) { + var h = Promise._handler(p); + return h.state() === 0 ? toPromise(p).then(state.fulfilled, state.rejected) + : state.inspect(h); + } + + /** + * Traditional reduce function, similar to `Array.prototype.reduce()`, but + * input may contain promises and/or values, and reduceFunc + * may return either a value or a promise, *and* initialValue may + * be a promise for the starting value. + * @param {Array|Promise} promises array or promise for an array of anything, + * may contain a mix of promises and values. + * @param {function(accumulated:*, x:*, index:Number):*} f reduce function + * @returns {Promise} that will resolve to the final reduced value + */ + function reduce(promises, f /*, initialValue */) { + return arguments.length > 2 ? ar.call(promises, liftCombine(f), arguments[2]) + : ar.call(promises, liftCombine(f)); + } + + /** + * Traditional reduce function, similar to `Array.prototype.reduceRight()`, but + * input may contain promises and/or values, and reduceFunc + * may return either a value or a promise, *and* initialValue may + * be a promise for the starting value. + * @param {Array|Promise} promises array or promise for an array of anything, + * may contain a mix of promises and values. + * @param {function(accumulated:*, x:*, index:Number):*} f reduce function + * @returns {Promise} that will resolve to the final reduced value + */ + function reduceRight(promises, f /*, initialValue */) { + return arguments.length > 2 ? arr.call(promises, liftCombine(f), arguments[2]) + : arr.call(promises, liftCombine(f)); + } + + function liftCombine(f) { + return function(z, x, i) { + return applyFold(f, void 0, [z,x,i]); + }; + } + }; + +}); +}(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(require); })); |
