UNPKG

when

Version:

A lightweight Promises/A+ and when() implementation, plus other async goodies.

1,695 lines (1,427 loc) 103 kB
!function(e){"object"==typeof exports?module.exports=e():"function"==typeof define&&define.amd?define(e):"undefined"!=typeof window?window.when=e():"undefined"!=typeof global?global.when=e():"undefined"!=typeof self&&(self.when=e())}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){ var when = module.exports = require('../when'); when.callbacks = require('../callbacks'); when.cancelable = require('../cancelable'); when.delay = require('../delay'); when.fn = require('../function'); when.guard = require('../guard'); when.keys = require('../keys'); when.nodefn = when.node = require('../node'); when.parallel = require('../parallel'); when.pipeline = require('../pipeline'); when.poll = require('../poll'); when.sequence = require('../sequence'); when.timeout = require('../timeout'); },{"../callbacks":2,"../cancelable":3,"../delay":4,"../function":5,"../guard":6,"../keys":7,"../node":26,"../parallel":27,"../pipeline":28,"../poll":29,"../sequence":30,"../timeout":31,"../when":32}],2:[function(require,module,exports){ /** @license MIT License (c) copyright 2013-2014 original author or authors */ /** * Collection of helper functions for interacting with 'traditional', * callback-taking functions using a promise interface. * * @author Renato Zannon * @contributor Brian Cavalier */ (function(define) { define(function(require) { var when = require('./when'); var Promise = when.Promise; var _liftAll = require('./lib/liftAll'); var slice = Array.prototype.slice; var makeApply = require('./lib/apply'); var _apply = makeApply(Promise, dispatch); return { lift: lift, liftAll: liftAll, apply: apply, call: call, promisify: promisify }; /** * Takes a `traditional` callback-taking function and returns a promise for its * result, accepting an optional array of arguments (that might be values or * promises). It assumes that the function takes its callback and errback as * the last two arguments. The resolution of the promise depends on whether the * function will call its callback or its errback. * * @example * var domIsLoaded = callbacks.apply($); * domIsLoaded.then(function() { * doMyDomStuff(); * }); * * @example * function existingAjaxyFunction(url, callback, errback) { * // Complex logic you'd rather not change * } * * var promise = callbacks.apply(existingAjaxyFunction, ["/movies.json"]); * * promise.then(function(movies) { * // Work with movies * }, function(reason) { * // Handle error * }); * * @param {function} asyncFunction function to be called * @param {Array} [extraAsyncArgs] array of arguments to asyncFunction * @returns {Promise} promise for the callback value of asyncFunction */ function apply(asyncFunction, extraAsyncArgs) { return _apply(asyncFunction, this, extraAsyncArgs || []); } /** * Apply helper that allows specifying thisArg * @private */ function dispatch(f, thisArg, args, h) { args.push(alwaysUnary(h.resolve, h), alwaysUnary(h.reject, h)); tryCatchResolve(f, thisArg, args, h); } function tryCatchResolve(f, thisArg, args, resolver) { try { f.apply(thisArg, args); } catch(e) { resolver.reject(e); } } /** * Works as `callbacks.apply` does, with the difference that the arguments to * the function are passed individually, instead of as an array. * * @example * function sumInFiveSeconds(a, b, callback) { * setTimeout(function() { * callback(a + b); * }, 5000); * } * * var sumPromise = callbacks.call(sumInFiveSeconds, 5, 10); * * // Logs '15' 5 seconds later * sumPromise.then(console.log); * * @param {function} asyncFunction function to be called * @param {...*} args arguments that will be forwarded to the function * @returns {Promise} promise for the callback value of asyncFunction */ function call(asyncFunction/*, arg1, arg2...*/) { return _apply(asyncFunction, this, slice.call(arguments, 1)); } /** * Takes a 'traditional' callback/errback-taking function and returns a function * that returns a promise instead. The resolution/rejection of the promise * depends on whether the original function will call its callback or its * errback. * * If additional arguments are passed to the `lift` call, they will be prepended * on the calls to the original function, much like `Function.prototype.bind`. * * The resulting function is also "promise-aware", in the sense that, if given * promises as arguments, it will wait for their resolution before executing. * * @example * function traditionalAjax(method, url, callback, errback) { * var xhr = new XMLHttpRequest(); * xhr.open(method, url); * * xhr.onload = callback; * xhr.onerror = errback; * * xhr.send(); * } * * var promiseAjax = callbacks.lift(traditionalAjax); * promiseAjax("GET", "/movies.json").then(console.log, console.error); * * var promiseAjaxGet = callbacks.lift(traditionalAjax, "GET"); * promiseAjaxGet("/movies.json").then(console.log, console.error); * * @param {Function} f traditional async function to be decorated * @param {...*} [args] arguments to be prepended for the new function @deprecated * @returns {Function} a promise-returning function */ function lift(f/*, args...*/) { var args = arguments.length > 1 ? slice.call(arguments, 1) : []; return function() { return _apply(f, this, args.concat(slice.call(arguments))); }; } /** * Lift all the functions/methods on src * @param {object|function} src source whose functions will be lifted * @param {function?} combine optional function for customizing the lifting * process. It is passed dst, the lifted function, and the property name of * the original function on src. * @param {(object|function)?} dst option destination host onto which to place lifted * functions. If not provided, liftAll returns a new object. * @returns {*} If dst is provided, returns dst with lifted functions as * properties. If dst not provided, returns a new object with lifted functions. */ function liftAll(src, combine, dst) { return _liftAll(lift, combine, dst, src); } /** * `promisify` is a version of `lift` that allows fine-grained control over the * arguments that passed to the underlying function. It is intended to handle * functions that don't follow the common callback and errback positions. * * The control is done by passing an object whose 'callback' and/or 'errback' * keys, whose values are the corresponding 0-based indexes of the arguments on * the function. Negative values are interpreted as being relative to the end * of the arguments array. * * If arguments are given on the call to the 'promisified' function, they are * intermingled with the callback and errback. If a promise is given among them, * the execution of the function will only occur after its resolution. * * @example * var delay = callbacks.promisify(setTimeout, { * callback: 0 * }); * * delay(100).then(function() { * console.log("This happens 100ms afterwards"); * }); * * @example * function callbackAsLast(errback, followsStandards, callback) { * if(followsStandards) { * callback("well done!"); * } else { * errback("some programmers just want to watch the world burn"); * } * } * * var promisified = callbacks.promisify(callbackAsLast, { * callback: -1, * errback: 0, * }); * * promisified(true).then(console.log, console.error); * promisified(false).then(console.log, console.error); * * @param {Function} asyncFunction traditional function to be decorated * @param {object} positions * @param {number} [positions.callback] index at which asyncFunction expects to * receive a success callback * @param {number} [positions.errback] index at which asyncFunction expects to * receive an error callback * @returns {function} promisified function that accepts * * @deprecated */ function promisify(asyncFunction, positions) { return function() { var thisArg = this; return Promise.all(arguments).then(function(args) { var p = Promise._defer(); var callbackPos, errbackPos; if(typeof positions.callback === 'number') { callbackPos = normalizePosition(args, positions.callback); } if(typeof positions.errback === 'number') { errbackPos = normalizePosition(args, positions.errback); } if(errbackPos < callbackPos) { insertCallback(args, errbackPos, p._handler.reject, p._handler); insertCallback(args, callbackPos, p._handler.resolve, p._handler); } else { insertCallback(args, callbackPos, p._handler.resolve, p._handler); insertCallback(args, errbackPos, p._handler.reject, p._handler); } asyncFunction.apply(thisArg, args); return p; }); }; } function normalizePosition(args, pos) { return pos < 0 ? (args.length + pos + 2) : pos; } function insertCallback(args, pos, callback, thisArg) { if(typeof pos === 'number') { args.splice(pos, 0, alwaysUnary(callback, thisArg)); } } function alwaysUnary(fn, thisArg) { return function() { if (arguments.length > 1) { fn.call(thisArg, slice.call(arguments)); } else { fn.apply(thisArg, arguments); } }; } }); })(typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); }); },{"./lib/apply":11,"./lib/liftAll":23,"./when":32}],3:[function(require,module,exports){ /** @license MIT License (c) copyright B Cavalier & J Hann */ /** * cancelable.js * @deprecated * * Decorator that makes a deferred "cancelable". It adds a cancel() method that * will call a special cancel handler function and then reject the deferred. The * cancel handler can be used to do resource cleanup, or anything else that should * be done before any other rejection handlers are executed. * * Usage: * * var cancelableDeferred = cancelable(when.defer(), myCancelHandler); * * @author brian@hovercraftstudios.com */ (function(define) { define(function() { /** * Makes deferred cancelable, adding a cancel() method. * @deprecated * * @param deferred {Deferred} the {@link Deferred} to make cancelable * @param canceler {Function} cancel handler function to execute when this deferred * is canceled. This is guaranteed to run before all other rejection handlers. * The canceler will NOT be executed if the deferred is rejected in the standard * way, i.e. deferred.reject(). It ONLY executes if the deferred is canceled, * i.e. deferred.cancel() * * @returns deferred, with an added cancel() method. */ return function(deferred, canceler) { // Add a cancel method to the deferred to reject the delegate // with the special canceled indicator. deferred.cancel = function() { try { deferred.reject(canceler(deferred)); } catch(e) { deferred.reject(e); } return deferred.promise; }; return deferred; }; }); })(typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(); }); },{}],4:[function(require,module,exports){ /** @license MIT License (c) copyright 2011-2013 original author or authors */ /** * delay.js * * Helper that returns a promise that resolves after a delay. * * @author Brian Cavalier * @author John Hann */ (function(define) { define(function(require) { var when = require('./when'); /** * @deprecated Use when(value).delay(ms) */ return function delay(msec, value) { return when(value).delay(msec); }; }); })(typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); }); },{"./when":32}],5:[function(require,module,exports){ /** @license MIT License (c) copyright 2013-2014 original author or authors */ /** * Collection of helper functions for wrapping and executing 'traditional' * synchronous functions in a promise interface. * * @author Brian Cavalier * @contributor Renato Zannon */ (function(define) { define(function(require) { var when = require('./when'); var attempt = when['try']; var _liftAll = require('./lib/liftAll'); var _apply = require('./lib/apply')(when.Promise); var slice = Array.prototype.slice; return { lift: lift, liftAll: liftAll, call: attempt, apply: apply, compose: compose }; /** * Takes a function and an optional array of arguments (that might be promises), * and calls the function. The return value is a promise whose resolution * depends on the value returned by the function. * @param {function} f function to be called * @param {Array} [args] array of arguments to func * @returns {Promise} promise for the return value of func */ function apply(f, args) { // slice args just in case the caller passed an Arguments instance return _apply(f, this, args == null ? [] : slice.call(args)); } /** * Takes a 'regular' function and returns a version of that function that * returns a promise instead of a plain value, and handles thrown errors by * returning a rejected promise. Also accepts a list of arguments to be * prepended to the new function, as does Function.prototype.bind. * * The resulting function is promise-aware, in the sense that it accepts * promise arguments, and waits for their resolution. * @param {Function} f function to be bound * @param {...*} [args] arguments to be prepended for the new function @deprecated * @returns {Function} a promise-returning function */ function lift(f /*, args... */) { var args = arguments.length > 1 ? slice.call(arguments, 1) : []; return function() { return _apply(f, this, args.concat(slice.call(arguments))); }; } /** * Lift all the functions/methods on src * @param {object|function} src source whose functions will be lifted * @param {function?} combine optional function for customizing the lifting * process. It is passed dst, the lifted function, and the property name of * the original function on src. * @param {(object|function)?} dst option destination host onto which to place lifted * functions. If not provided, liftAll returns a new object. * @returns {*} If dst is provided, returns dst with lifted functions as * properties. If dst not provided, returns a new object with lifted functions. */ function liftAll(src, combine, dst) { return _liftAll(lift, combine, dst, src); } /** * Composes multiple functions by piping their return values. It is * transparent to whether the functions return 'regular' values or promises: * the piped argument is always a resolved value. If one of the functions * throws or returns a rejected promise, the composed promise will be also * rejected. * * The arguments (or promises to arguments) given to the returned function (if * any), are passed directly to the first function on the 'pipeline'. * @param {Function} f the function to which the arguments will be passed * @param {...Function} [funcs] functions that will be composed, in order * @returns {Function} a promise-returning composition of the functions */ function compose(f /*, funcs... */) { var funcs = slice.call(arguments, 1); return function() { var thisArg = this; var args = slice.call(arguments); var firstPromise = attempt.apply(thisArg, [f].concat(args)); return when.reduce(funcs, function(arg, func) { return func.call(thisArg, arg); }, firstPromise); }; } }); })(typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); }); },{"./lib/apply":11,"./lib/liftAll":23,"./when":32}],6:[function(require,module,exports){ /** @license MIT License (c) copyright 2011-2013 original author or authors */ /** * Generalized promise concurrency guard * Adapted from original concept by Sakari Jokinen (Rocket Pack, Ltd.) * * @author Brian Cavalier * @author John Hann * @contributor Sakari Jokinen */ (function(define) { define(function(require) { var when = require('./when'); var slice = Array.prototype.slice; guard.n = n; return guard; /** * Creates a guarded version of f that can only be entered when the supplied * condition allows. * @param {function} condition represents a critical section that may only * be entered when allowed by the condition * @param {function} f function to guard * @returns {function} guarded version of f */ function guard(condition, f) { return function() { var args = slice.call(arguments); return when(condition()).withThis(this).then(function(exit) { return when(f.apply(this, args))['finally'](exit); }); }; } /** * Creates a condition that allows only n simultaneous executions * of a guarded function * @param {number} allowed number of allowed simultaneous executions * @returns {function} condition function which returns a promise that * fulfills when the critical section may be entered. The fulfillment * value is a function ("notifyExit") that must be called when the critical * section has been exited. */ function n(allowed) { var count = 0; var waiting = []; return function enter() { return when.promise(function(resolve) { if(count < allowed) { resolve(exit); } else { waiting.push(resolve); } count += 1; }); }; function exit() { count = Math.max(count - 1, 0); if(waiting.length > 0) { waiting.shift()(exit); } } } }); }(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(require); })); },{"./when":32}],7:[function(require,module,exports){ /** @license MIT License (c) copyright 2011-2013 original author or authors */ /** * Licensed under the MIT License at: * http://www.opensource.org/licenses/mit-license.php * * @author Brian Cavalier * @author John Hann */ (function(define) { 'use strict'; define(function(require) { var when = require('./when'); var Promise = when.Promise; var toPromise = when.resolve; return { all: when.lift(all), map: map, settle: settle }; /** * Resolve all the key-value pairs in the supplied object or promise * for an object. * @param {Promise|object} object or promise for object whose key-value pairs * will be resolved * @returns {Promise} promise for an object with the fully resolved key-value pairs */ function all(object) { var p = Promise._defer(); var resolver = Promise._handler(p); var results = {}; var keys = Object.keys(object); var pending = keys.length; for(var i=0, k; i<keys.length; ++i) { k = keys[i]; Promise._handler(object[k]).fold(settleKey, k, results, resolver); } if(pending === 0) { resolver.resolve(results); } return p; function settleKey(k, x, resolver) { /*jshint validthis:true*/ this[k] = x; if(--pending === 0) { resolver.resolve(results); } } } /** * Map values in the supplied object's keys * @param {Promise|object} object or promise for object whose key-value pairs * will be reduced * @param {function(value:*, key:String):*} f mapping function which may * return either a promise or a value * @returns {Promise} promise for an object with the mapped and fully * resolved key-value pairs */ function map(object, f) { return toPromise(object).then(function(object) { return all(Object.keys(object).reduce(function(o, k) { o[k] = toPromise(object[k]).fold(mapWithKey, k); return o; }, {})); }); function mapWithKey(k, x) { return f(x, k); } } /** * Resolve all key-value pairs in the supplied object and return a promise * that will always fulfill with the outcome states of all input promises. * @param {object} object whose key-value pairs will be settled * @returns {Promise} promise for an object with the mapped and fully * settled key-value pairs */ function settle(object) { var keys = Object.keys(object); var results = {}; if(keys.length === 0) { return toPromise(results); } var p = Promise._defer(); var resolver = Promise._handler(p); var promises = keys.map(function(k) { return object[k]; }); when.settle(promises).then(function(states) { populateResults(keys, states, results, resolver); }); return p; } function populateResults(keys, states, results, resolver) { for(var i=0; i<keys.length; i++) { results[keys[i]] = states[i]; } resolver.resolve(results); } }); })(typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); }); },{"./when":32}],8:[function(require,module,exports){ /** @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 makePromise = require('./makePromise'); var Scheduler = require('./Scheduler'); var async = require('./env').asap; return makePromise({ scheduler: new Scheduler(async) }); }); })(typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); }); },{"./Scheduler":9,"./env":21,"./makePromise":24}],9:[function(require,module,exports){ /** @license MIT License (c) copyright 2010-2014 original author or authors */ /** @author Brian Cavalier */ /** @author John Hann */ (function(define) { 'use strict'; define(function() { // Credit to Twisol (https://github.com/Twisol) for suggesting // this type of extensible queue + trampoline approach for next-tick conflation. /** * Async task scheduler * @param {function} async function to schedule a single async function * @constructor */ function Scheduler(async) { this._async = async; this._running = false; this._queue = this; this._queueLen = 0; this._afterQueue = {}; this._afterQueueLen = 0; var self = this; this.drain = function() { self._drain(); }; } /** * Enqueue a task * @param {{ run:function }} task */ Scheduler.prototype.enqueue = function(task) { this._queue[this._queueLen++] = task; this.run(); }; /** * Enqueue a task to run after the main task queue * @param {{ run:function }} task */ Scheduler.prototype.afterQueue = function(task) { this._afterQueue[this._afterQueueLen++] = task; this.run(); }; Scheduler.prototype.run = function() { if (!this._running) { this._running = true; this._async(this.drain); } }; /** * Drain the handler queue entirely, and then the after queue */ Scheduler.prototype._drain = function() { var i = 0; for (; i < this._queueLen; ++i) { this._queue[i].run(); this._queue[i] = void 0; } this._queueLen = 0; this._running = false; for (i = 0; i < this._afterQueueLen; ++i) { this._afterQueue[i].run(); this._afterQueue[i] = void 0; } this._afterQueueLen = 0; }; return Scheduler; }); }(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(); })); },{}],10:[function(require,module,exports){ /** @license MIT License (c) copyright 2010-2014 original author or authors */ /** @author Brian Cavalier */ /** @author John Hann */ (function(define) { 'use strict'; define(function() { /** * Custom error type for promises rejected by promise.timeout * @param {string} message * @constructor */ function TimeoutError (message) { Error.call(this); this.message = message; this.name = TimeoutError.name; if (typeof Error.captureStackTrace === 'function') { Error.captureStackTrace(this, TimeoutError); } } TimeoutError.prototype = Object.create(Error.prototype); TimeoutError.prototype.constructor = TimeoutError; return TimeoutError; }); }(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(); })); },{}],11:[function(require,module,exports){ /** @license MIT License (c) copyright 2010-2014 original author or authors */ /** @author Brian Cavalier */ /** @author John Hann */ (function(define) { 'use strict'; define(function() { makeApply.tryCatchResolve = tryCatchResolve; return makeApply; function makeApply(Promise, call) { if(arguments.length < 2) { call = tryCatchResolve; } return apply; function apply(f, thisArg, args) { var p = Promise._defer(); var l = args.length; var params = new Array(l); callAndResolve({ f:f, thisArg:thisArg, args:args, params:params, i:l-1, call:call }, p._handler); return p; } function callAndResolve(c, h) { if(c.i < 0) { return call(c.f, c.thisArg, c.params, h); } var handler = Promise._handler(c.args[c.i]); handler.fold(callAndResolveNext, c, void 0, h); } function callAndResolveNext(c, x, h) { c.params[c.i] = x; c.i -= 1; callAndResolve(c, h); } } function tryCatchResolve(f, thisArg, args, resolver) { try { resolver.resolve(f.apply(thisArg, args)); } catch(e) { resolver.reject(e); } } }); }(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(); })); },{}],12:[function(require,module,exports){ /** @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) { // Optimize the case where we get an already-resolved when.js promise // by extracting its state: var handler; if (p instanceof Promise) { // This is our own Promise type and we can reach its handler internals: handler = p._handler.join(); } if((handler && handler.state() === 0) || !handler) { // Either still pending, or not a Promise at all: return toPromise(p).then(state.fulfilled, state.rejected); } // The promise is our own, but it is already resolved. Take a shortcut. // Since we're not actually handling the resolution, we need to disable // rejection reporting. handler._unreport(); return state.inspect(handler); } /** * 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); })); },{"../apply":11,"../state":25}],13:[function(require,module,exports){ /** @license MIT License (c) copyright 2010-2014 original author or authors */ /** @author Brian Cavalier */ /** @author John Hann */ (function(define) { 'use strict'; define(function() { return function flow(Promise) { var resolve = Promise.resolve; var reject = Promise.reject; var origCatch = Promise.prototype['catch']; /** * Handle the ultimate fulfillment value or rejection reason, and assume * responsibility for all errors. If an error propagates out of result * or handleFatalError, it will be rethrown to the host, resulting in a * loud stack track on most platforms and a crash on some. * @param {function?} onResult * @param {function?} onError * @returns {undefined} */ Promise.prototype.done = function(onResult, onError) { this._handler.visit(this._handler.receiver, onResult, onError); }; /** * Add Error-type and predicate matching to catch. Examples: * promise.catch(TypeError, handleTypeError) * .catch(predicate, handleMatchedErrors) * .catch(handleRemainingErrors) * @param onRejected * @returns {*} */ Promise.prototype['catch'] = Promise.prototype.otherwise = function(onRejected) { if (arguments.length < 2) { return origCatch.call(this, onRejected); } if(typeof onRejected !== 'function') { return this.ensure(rejectInvalidPredicate); } return origCatch.call(this, createCatchFilter(arguments[1], onRejected)); }; /** * Wraps the provided catch handler, so that it will only be called * if the predicate evaluates truthy * @param {?function} handler * @param {function} predicate * @returns {function} conditional catch handler */ function createCatchFilter(handler, predicate) { return function(e) { return evaluatePredicate(e, predicate) ? handler.call(this, e) : reject(e); }; } /** * Ensures that onFulfilledOrRejected will be called regardless of whether * this promise is fulfilled or rejected. onFulfilledOrRejected WILL NOT * receive the promises' value or reason. Any returned value will be disregarded. * onFulfilledOrRejected may throw or return a rejected promise to signal * an additional error. * @param {function} handler handler to be called regardless of * fulfillment or rejection * @returns {Promise} */ Promise.prototype['finally'] = Promise.prototype.ensure = function(handler) { if(typeof handler !== 'function') { return this; } return this.then(function(x) { return runSideEffect(handler, this, identity, x); }, function(e) { return runSideEffect(handler, this, reject, e); }); }; function runSideEffect (handler, thisArg, propagate, value) { var result = handler.call(thisArg); return maybeThenable(result) ? propagateValue(result, propagate, value) : propagate(value); } function propagateValue (result, propagate, x) { return resolve(result).then(function () { return propagate(x); }); } /** * Recover from a failure by returning a defaultValue. If defaultValue * is a promise, it's fulfillment value will be used. If defaultValue is * a promise that rejects, the returned promise will reject with the * same reason. * @param {*} defaultValue * @returns {Promise} new promise */ Promise.prototype['else'] = Promise.prototype.orElse = function(defaultValue) { return this.then(void 0, function() { return defaultValue; }); }; /** * Shortcut for .then(function() { return value; }) * @param {*} value * @return {Promise} a promise that: * - is fulfilled if value is not a promise, or * - if value is a promise, will fulfill with its value, or reject * with its reason. */ Promise.prototype['yield'] = function(value) { return this.then(function() { return value; }); }; /** * Runs a side effect when this promise fulfills, without changing the * fulfillment value. * @param {function} onFulfilledSideEffect * @returns {Promise} */ Promise.prototype.tap = function(onFulfilledSideEffect) { return this.then(onFulfilledSideEffect)['yield'](this); }; return Promise; }; function rejectInvalidPredicate() { throw new TypeError('catch predicate must be a function'); } function evaluatePredicate(e, predicate) { return isError(predicate) ? e instanceof predicate : predicate(e); } function isError(predicate) { return predicate === Error || (predicate != null && predicate.prototype instanceof Error); } function maybeThenable(x) { return (typeof x === 'object' || typeof x === 'function') && x !== null; } function identity(x) { return x; } }); }(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(); })); },{}],14:[function(require,module,exports){ /** @license MIT License (c) copyright 2010-2014 original author or authors */ /** @author Brian Cavalier */ /** @author John Hann */ /** @author Jeff Escalante */ (function(define) { 'use strict'; define(function() { return function fold(Promise) { Promise.prototype.fold = function(f, z) { var promise = this._beget(); this._handler.fold(function(z, x, to) { Promise._handler(z).fold(function(x, z, to) { to.resolve(f.call(this, z, x)); }, x, this, to); }, z, promise._handler.receiver, promise._handler); return promise; }; return Promise; }; }); }(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(); })); },{}],15:[function(require,module,exports){ /** @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 inspect = require('../state').inspect; return function inspection(Promise) { Promise.prototype.inspect = function() { return inspect(Promise._handler(this)); }; return Promise; }; }); }(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(require); })); },{"../state":25}],16:[function(require,module,exports){ /** @license MIT License (c) copyright 2010-2014 original author or authors */ /** @author Brian Cavalier */ /** @author John Hann */ (function(define) { 'use strict'; define(function() { return function generate(Promise) { var resolve = Promise.resolve; Promise.iterate = iterate; Promise.unfold = unfold; return Promise; /** * @deprecated Use github.com/cujojs/most streams and most.iterate * Generate a (potentially infinite) stream of promised values: * x, f(x), f(f(x)), etc. until condition(x) returns true * @param {function} f function to generate a new x from the previous x * @param {function} condition function that, given the current x, returns * truthy when the iterate should stop * @param {function} handler function to handle the value produced by f * @param {*|Promise} x starting value, may be a promise * @return {Promise} the result of the last call to f before * condition returns true */ function iterate(f, condition, handler, x) { return unfold(function(x) { return [x, f(x)]; }, condition, handler, x); } /** * @deprecated Use github.com/cujojs/most streams and most.unfold * Generate a (potentially infinite) stream of promised values * by applying handler(generator(seed)) iteratively until * condition(seed) returns true. * @param {function} unspool function that generates a [value, newSeed] * given a seed. * @param {function} condition function that, given the current seed, returns * truthy when the unfold should stop * @param {function} handler function to handle the value produced by unspool * @param x {*|Promise} starting value, may be a promise * @return {Promise} the result of the last value produced by unspool before * condition returns true */ function unfold(unspool, condition, handler, x) { return resolve(x).then(function(seed) { return resolve(condition(seed)).then(function(done) { return done ? seed : resolve(unspool(seed)).spread(next); }); }); function next(item, newSeed) { return resolve(handler(item)).then(function() { return unfold(unspool, condition, handler, newSeed); }); } } }; }); }(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(); })); },{}],17:[function(require,module,exports){ /** @license MIT License (c) copyright 2010-2014 original author or authors */ /** @author Brian Cavalier */ /** @author John Hann */ (function(define) { 'use strict'; define(function() { return function progress(Promise) { /** * @deprecated * Register a progress handler for this promise * @param {function} onProgress * @returns {Promise} */ Promise.prototype.progress = function(onProgress) { return this.then(void 0, void 0, onProgress); }; return Promise; }; }); }(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(); })); },{}],18:[function(require,module,exports){ /** @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 env = require('../env'); var TimeoutError = require('../TimeoutError'); function setTimeout(f, ms, x, y) { return env.setTimer(function() { f(x, y, ms); }, ms); } return function timed(Promise) { /** * Return a new promise whose fulfillment value is revealed only * after ms milliseconds * @param {number} ms milliseconds * @returns {Promise} */ Promise.prototype.delay = function(ms) { var p = this._beget(); this._handler.fold(handleDelay, ms, void 0, p._handler); return p; }; function handleDelay(ms, x, h) { setTimeout(resolveDelay, ms, x, h); } function resolveDelay(x, h) { h.resolve(x); } /** * Return a new promise that rejects after ms milliseconds unless * this promise fulfills earlier, in which case the returned promise * fulfills with the same value. * @param {number} ms milliseconds * @param {Error|*=} reason optional rejection reason to use, defaults * to a TimeoutError if not provided * @returns {Promise} */ Promise.prototype.timeout = function(ms, reason) { var p = this._beget(); var h = p._handler; var t = setTimeout(onTimeout, ms, reason, p._handler); this._handler.visit(h, function onFulfill(x) { env.clearTimer(t); this.resolve(x); // this = h }, function onReject(x) { env.clearTimer(t); this.reject(x); // this = h }, h.notify); return p; }; function onTimeout(reason, h, ms) { var e = typeof reason === 'undefined' ? new TimeoutError('timed out after ' + ms + 'ms') : reason; h.reject(e); } return Promise; }; }); }(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(require); })); },{"../TimeoutError":10,"../env":21}],19:[function(require,module,exports){ /** @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 setTimer = require('../env').setTimer; var format = require('../format'); return function unhandledRejection(Promise) { var logError = noop; var logInfo = noop; var localConsole; if(typeof console !== 'undefined') { // Alias console to prevent things like uglify's drop_console option from // removing console.log/error. Unhandled rejections fall into the same // category as uncaught exceptions, and build tools shouldn't silence them. localConsole = console; logError = typeof localConsole.error !== 'undefined' ? function (e) { localConsole.error(e); } : function (e) { localConsole.log(e); }; logInfo = typeof localConsole.info !== 'undefined' ? function (e) { localConsole.info(e); } : function (e) { localConsole.log(e); }; } Promise.onPotentiallyUnhandledRejection = function(rejection) { enqueue(report, rejection); }; Promise.onPotentiallyUnhandledRejectionHandled = function(rejection) { enqueue(unreport, rejection); }; Promise.onFatalRejection = function(rejection) { enqueue(throwit, rejection.value); }; var tasks = []; var reported = []; var running = null; function report(r) { if(!r.handled) { reported.push(r); logError('Potentially unhandled rejection [' + r.id + '] ' + format.formatError(r.value)); } } function unreport(r) { var i = reported.indexOf(r); if(i >= 0) { reported.splice(i, 1); logInfo('Handled previous rejection [' + r.id + '] ' + format.formatObject(r.value)); } } function enqueue(f, x) { tasks.push(f, x); if(running === null) { running = setTimer(flush, 0); } } function flush() { running = null; while(tasks.length > 0) { tasks.shift()(tasks.shift()); } } return Promise; }; function throwit(e) { throw e; } function noop() {} }); }(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(require); })); },{"../env":21,"../format":22}],20:[function(require,module,exports){ /** @license MIT License (c) copyright 2010-2014 original author or authors */ /** @author Brian Cavalier */ /** @author John Hann */ (function(define) { 'use strict'; define(function() { return function addWith(Promise) { /** * Returns a promise whose handlers will be called with `this` set to * the supplied receiver. Subsequent promises derived from the * returned promise will also have their handlers called with receiver * as `this`. Calling `with` with undefined or no arguments will return * a promise whose handlers will again be called in the usual Promises/A+ * way (no `this`) thus safely undoing any previous `with` in the * promise chain. * * WARNING: Promises returned from `with`/`withThis` are NOT Promises/A+ * compliant, specifically violating 2.2.5 (http://promisesaplus.com/#point-41) * * @param {object} receiver `this` value for all handlers attached to * the returned promise. * @returns {Promise} */ Promise.prototype['with'] = Promise.prototype.withThis = function(receiver) { var p = this._beget(); var child = p._handler; child.receiver = receiver; this._handler.chain(child, receiver); return p; }; return Promise; }; }); }(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(); })); },{}],21:[function(require,module,exports){ /** @license MIT License (c) copyright 2010-2014 original author or authors */ /** @author Brian Cavalier */ /** @author John Hann */ /*global process,document,setTimeout,clearTimeout,MutationObserver,WebKitMutationObserver*/ (function(define) { 'use strict'; define(function(require) { /*jshint maxcomplexity:6*/ // Sniff "best" async scheduling option // Prefer process.nextTick or MutationObserver, then check for // setTimeout, and finally vertx, since its the only env that doesn't // have setTimeout var MutationObs; var capturedSetTimeout = typeof setTimeout !== 'undefined' && setTimeout; // Default env var setTimer = function(f, ms) { return setTimeout(f, ms); }; var clearTimer = function(t) { return clearTimeout(t); }; var asap = function (f) { return capturedSetTimeout(f, 0); }; // Detect specific env if (isNode()) { // Node asap = function (f) { return process.nextTick(f); }; } else if (MutationObs = hasMutationObserver()) { // Modern browser asap = initMutationObserver(MutationObs); } else if (!capturedSetTimeout) { // vert.x var vertxRequire = require; var vertx = vertxRequi