Comparing version 2.8.0 to 3.0.0
{ | ||
"name": "when", | ||
"version": "3.0.0", | ||
"main": "when.js", | ||
"version": "2.8.0", | ||
"moduleType": ["amd", "node"], | ||
"description": "A lightweight Promises/A+ and when() implementation, plus other async goodies.", | ||
@@ -6,0 +7,0 @@ "keywords": ["Promises/A+", "promises-aplus", "promise", "promises", "deferred", "deferreds", "when", "async", "asynchronous", "cujo"], |
100
callbacks.js
@@ -1,10 +0,8 @@ | ||
/** @license MIT License (c) copyright 2013 original author or authors */ | ||
/** @license MIT License (c) copyright 2013-2014 original author or authors */ | ||
/** | ||
* callbacks.js | ||
* | ||
* Collection of helper functions for interacting with 'traditional', | ||
* callback-taking functions using a promise interface. | ||
* | ||
* @author Renato Zannon <renato.riccieri@gmail.com> | ||
* @author Renato Zannon | ||
* @contributor Brian Cavalier | ||
@@ -16,13 +14,15 @@ */ | ||
var when, promise, slice; | ||
var when, Promise, promise, slice, _liftAll; | ||
when = require('./when'); | ||
Promise = when.Promise; | ||
_liftAll = require('./lib/liftAll'); | ||
promise = when.promise; | ||
slice = [].slice; | ||
slice = Array.prototype.slice; | ||
return { | ||
lift: lift, | ||
liftAll: liftAll, | ||
apply: apply, | ||
call: call, | ||
lift: lift, | ||
bind: lift, // DEPRECATED alias for lift | ||
promisify: promisify | ||
@@ -62,3 +62,3 @@ }; | ||
function apply(asyncFunction, extraAsyncArgs) { | ||
return _apply(asyncFunction, this, extraAsyncArgs); | ||
return _apply(asyncFunction, this, extraAsyncArgs || []); | ||
} | ||
@@ -71,11 +71,9 @@ | ||
function _apply(asyncFunction, thisArg, extraAsyncArgs) { | ||
return when.all(extraAsyncArgs || []).then(function(args) { | ||
return promise(function(resolve, reject) { | ||
var asyncArgs = args.concat( | ||
alwaysUnary(resolve), | ||
alwaysUnary(reject) | ||
); | ||
return Promise.all(extraAsyncArgs).then(function(args) { | ||
var p = Promise._defer(); | ||
args.push(alwaysUnary(p._handler.resolve, p._handler), | ||
alwaysUnary(p._handler.reject, p._handler)); | ||
asyncFunction.apply(thisArg, args); | ||
asyncFunction.apply(thisArg, asyncArgs); | ||
}); | ||
return p; | ||
}); | ||
@@ -149,2 +147,17 @@ } | ||
/** | ||
* 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 | ||
@@ -201,27 +214,26 @@ * arguments that passed to the underlying function. It is intended to handle | ||
var thisArg = this; | ||
return when.all(arguments).then(function(args) { | ||
return promise(applyPromisified); | ||
return Promise.all(arguments).then(function(args) { | ||
var p = Promise._defer(); | ||
function applyPromisified(resolve, reject) { | ||
var callbackPos, errbackPos; | ||
var callbackPos, errbackPos; | ||
if('callback' in positions) { | ||
callbackPos = normalizePosition(args, positions.callback); | ||
} | ||
if('callback' in positions) { | ||
callbackPos = normalizePosition(args, positions.callback); | ||
} | ||
if('errback' in positions) { | ||
errbackPos = normalizePosition(args, positions.errback); | ||
} | ||
if('errback' in positions) { | ||
errbackPos = normalizePosition(args, positions.errback); | ||
} | ||
if(errbackPos < callbackPos) { | ||
insertCallback(args, errbackPos, reject); | ||
insertCallback(args, callbackPos, resolve); | ||
} else { | ||
insertCallback(args, callbackPos, resolve); | ||
insertCallback(args, errbackPos, reject); | ||
} | ||
asyncFunction.apply(thisArg, args); | ||
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; | ||
}); | ||
@@ -235,5 +247,5 @@ }; | ||
function insertCallback(args, pos, callback) { | ||
function insertCallback(args, pos, callback, thisArg) { | ||
if(pos != null) { | ||
callback = alwaysUnary(callback); | ||
callback = alwaysUnary(callback, thisArg); | ||
if(pos < 0) { | ||
@@ -244,11 +256,10 @@ pos = args.length + pos + 2; | ||
} | ||
} | ||
function alwaysUnary(fn) { | ||
function alwaysUnary(fn, thisArg) { | ||
return function() { | ||
if(arguments.length <= 1) { | ||
fn.apply(this, arguments); | ||
fn.apply(thisArg, arguments); | ||
} else { | ||
fn.call(this, slice.call(arguments)); | ||
fn.call(thisArg, slice.call(arguments)); | ||
} | ||
@@ -258,5 +269,2 @@ }; | ||
}); | ||
})( | ||
typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); } | ||
// Boilerplate for AMD and Node | ||
); | ||
})(typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); }); |
@@ -5,2 +5,3 @@ /** @license MIT License (c) copyright B Cavalier & J Hann */ | ||
* cancelable.js | ||
* @deprecated | ||
* | ||
@@ -20,8 +21,7 @@ * Decorator that makes a deferred "cancelable". It adds a cancel() method that | ||
(function(define) { | ||
define(function(require) { | ||
define(function() { | ||
var when = require('./when'); | ||
/** | ||
* Makes deferred cancelable, adding a cancel() method. | ||
* @deprecated | ||
* | ||
@@ -38,18 +38,14 @@ * @param deferred {Deferred} the {@link Deferred} to make cancelable | ||
return function(deferred, canceler) { | ||
var delegate = when.defer(); | ||
// Add a cancel method to the deferred to reject the delegate | ||
// with the special canceled indicator. | ||
deferred.cancel = function() { | ||
return deferred.reject(canceler(deferred)); | ||
try { | ||
deferred.reject(canceler(deferred)); | ||
} catch(e) { | ||
deferred.reject(e); | ||
} | ||
return deferred.promise; | ||
}; | ||
// Ensure that the original resolve, reject, and progress all forward | ||
// to the delegate | ||
deferred.promise.then(delegate.resolve, delegate.reject, delegate.notify); | ||
// Replace deferred's promise with the delegate promise | ||
deferred.promise = delegate.promise; | ||
return deferred; | ||
@@ -59,7 +55,4 @@ }; | ||
}); | ||
})( | ||
typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); } | ||
// Boilerplate for AMD and Node | ||
); | ||
})(typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(); }); | ||
@@ -0,1 +1,13 @@ | ||
### 3.0.0 | ||
* New internal architecture with significant performance improvements and memory efficiency | ||
* New APIs | ||
* [`when.try`](docs/api.md#whentry), [`when.lift`](docs/api.md#whenlift), [`when.reduceRight`](docs/api.md#whenreduceRight), [`when.iterate`](docs/api.md#wheniterate), [`when.unfold`](docs/api.md#whenunfold), [`when.race`](docs/api.md#whenrace) | ||
* [`promise.with`](docs/api.md#promisewith), [`promise.else`](docs/api.md#promiseelse), [`promise.delay`](docs/api.md#promisedelay), [`promise.timeout`](docs/api.md#promisetimeout), [`promise.progress`](docs/api.md#promiseprogress) | ||
* New liftAll variants for lifting all of an object's functions in one shot, eg. `var promisedFs = node.liftAll(require('fs'))` | ||
* [`fn.liftAll`](docs/api.md#fnliftall), [`node.liftAll`](docs/api.md#nodeliftall), [`callbacks.liftAll`](docs/api.md#callbacksliftall) | ||
* `when.Promise` public, inheritance-friendly, Promise constructor | ||
* New [ES6 Promise shim](docs/es6-promise-shim.md) | ||
* Check out the [tips for upgrading to 3.0 from 2.x](docs/api.md#upgrading-to-30-from-2x) | ||
### 2.8.0 | ||
@@ -2,0 +14,0 @@ |
41
delay.js
@@ -14,48 +14,15 @@ /** @license MIT License (c) copyright 2011-2013 original author or authors */ | ||
define(function(require) { | ||
/*global setTimeout*/ | ||
var when, setTimer, cjsRequire, vertxSetTimer; | ||
when = require('./when'); | ||
cjsRequire = require; | ||
var resolve = require('./when').resolve; | ||
try { | ||
vertxSetTimer = cjsRequire('vertx').setTimer; | ||
setTimer = function (f, ms) { return vertxSetTimer(ms, f); }; | ||
} catch(e) { | ||
setTimer = setTimeout; | ||
} | ||
/** | ||
* Creates a new promise that will resolve after a msec delay. If | ||
* value is supplied, the delay will start *after* the supplied | ||
* value is resolved. | ||
* | ||
* @param {number} msec delay in milliseconds | ||
* @param {*|Promise?} value any promise or value after which | ||
* the delay will start | ||
* @returns {Promise} promise that is equivalent to value, only delayed | ||
* by msec | ||
* @deprecated Use when(value).delay(ms) | ||
*/ | ||
return function delay(msec, value) { | ||
// Support reversed, deprecated argument ordering | ||
if(typeof value === 'number') { | ||
var tmp = value; | ||
value = msec; | ||
msec = tmp; | ||
} | ||
return when.promise(function(resolve, reject, notify) { | ||
when(value, function(val) { | ||
setTimer(function() { | ||
resolve(val); | ||
}, msec); | ||
}, | ||
reject, notify); | ||
}); | ||
return resolve(value).delay(msec); | ||
}; | ||
}); | ||
})( | ||
typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); }); | ||
})(typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); }); | ||
186
function.js
@@ -1,11 +0,9 @@ | ||
/** @license MIT License (c) copyright 2013 original author or authors */ | ||
/** @license MIT License (c) copyright 2013-2014 original author or authors */ | ||
/** | ||
* function.js | ||
* | ||
* Collection of helper functions for wrapping and executing 'traditional' | ||
* synchronous functions in a promise interface. | ||
* | ||
* @author brian@hovercraftstudios.com | ||
* @contributor renato.riccieri@gmail.com | ||
* @author Brian Cavalier | ||
* @contributor Renato Zannon | ||
*/ | ||
@@ -16,12 +14,14 @@ | ||
var when, slice; | ||
var when, slice, attempt, _liftAll; | ||
when = require('./when'); | ||
slice = [].slice; | ||
attempt = when['try']; | ||
_liftAll = require('./lib/liftAll'); | ||
slice = Array.prototype.slice; | ||
return { | ||
lift: lift, | ||
liftAll: liftAll, | ||
call: attempt, | ||
apply: apply, | ||
call: call, | ||
lift: lift, | ||
bind: lift, // DEPRECATED alias for lift | ||
compose: compose | ||
@@ -34,65 +34,11 @@ }; | ||
* depends on the value returned by the function. | ||
* | ||
* @example | ||
* function onlySmallNumbers(n) { | ||
* if(n < 10) { | ||
* return n + 10; | ||
* } else { | ||
* throw new Error("Calculation failed"); | ||
* } | ||
* } | ||
* | ||
* // Logs '15' | ||
* func.apply(onlySmallNumbers, [5]).then(console.log, console.error); | ||
* | ||
* // Logs 'Calculation failed' | ||
* func.apply(onlySmallNumbers, [15]).then(console.log, console.error); | ||
* | ||
* @param {function} func function to be called | ||
* @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(func, promisedArgs) { | ||
return _apply(func, this, promisedArgs); | ||
function apply(f, args) { | ||
return _apply(f, this, args || []); | ||
} | ||
/** | ||
* Apply helper that allows specifying thisArg | ||
* @private | ||
*/ | ||
function _apply(func, thisArg, promisedArgs) { | ||
return when.all(promisedArgs || [], function(args) { | ||
return func.apply(thisArg, args); | ||
}); | ||
} | ||
/** | ||
* Has the same behavior that {@link apply} has, with the difference that the | ||
* arguments to the function are provided individually, while {@link apply} accepts | ||
* a single array. | ||
* | ||
* @example | ||
* function sumSmallNumbers(x, y) { | ||
* var result = x + y; | ||
* if(result < 10) { | ||
* return result; | ||
* } else { | ||
* throw new Error("Calculation failed"); | ||
* } | ||
* } | ||
* | ||
* // Logs '5' | ||
* func.apply(sumSmallNumbers, 2, 3).then(console.log, console.error); | ||
* | ||
* // Logs 'Calculation failed' | ||
* func.apply(sumSmallNumbers, 5, 10).then(console.log, console.error); | ||
* | ||
* @param {function} func function to be called | ||
* @param {...*} [args] arguments that will be forwarded to the function | ||
* @returns {Promise} promise for the return value of func | ||
*/ | ||
function call(func /*, args... */) { | ||
return _apply(func, this, slice.call(arguments, 1)); | ||
} | ||
/** | ||
* Takes a 'regular' function and returns a version of that function that | ||
@@ -105,38 +51,10 @@ * returns a promise instead of a plain value, and handles thrown errors by | ||
* promise arguments, and waits for their resolution. | ||
* | ||
* @example | ||
* function mayThrowError(n) { | ||
* if(n % 2 === 1) { // Normally this wouldn't be so deterministic :) | ||
* throw new Error("I don't like odd numbers"); | ||
* } else { | ||
* return n; | ||
* } | ||
* } | ||
* | ||
* var lifted = fn.lift(mayThrowError); | ||
* | ||
* // Logs "I don't like odd numbers" | ||
* lifted(1).then(console.log, console.error); | ||
* | ||
* // Logs '6' | ||
* lifted(6).then(console.log, console.error); | ||
* | ||
* @example | ||
* function sumTwoNumbers(x, y) { | ||
* return x + y; | ||
* } | ||
* | ||
* var sumWithFive = fn.lifted(sumTwoNumbers, 5); | ||
* | ||
* // Logs '15' | ||
* sumWithFive(10).then(console.log, console.error); | ||
* | ||
* @param {Function} func function to be bound | ||
* @param {...*} [args] arguments to be prepended for the new function | ||
* @returns {Function} a promise-returning function | ||
* @param {Function} f function to be bound | ||
* @param {...*} [args] arguments to be prepended for the new function | ||
* @returns {Function} a promise-returning function | ||
*/ | ||
function lift(func /*, args... */) { | ||
function lift(f /*, args... */) { | ||
var args = slice.call(arguments, 1); | ||
return function() { | ||
return _apply(func, this, args.concat(slice.call(arguments))); | ||
return _apply(f, this, args.concat(slice.call(arguments))); | ||
}; | ||
@@ -146,2 +64,27 @@ } | ||
/** | ||
* Apply helper that allows specifying thisArg | ||
* @private | ||
*/ | ||
function _apply(f, thisArg, args) { | ||
return args.length === 0 | ||
? attempt.call(thisArg, f) | ||
: attempt.apply(thisArg, [f].concat(args)); | ||
} | ||
/** | ||
* 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 | ||
@@ -155,37 +98,2 @@ * transparent to whether the functions return 'regular' values or promises: | ||
* any), are passed directly to the first function on the 'pipeline'. | ||
* | ||
* @example | ||
* function getHowMuchWeWillDestroy(parameter) { | ||
* // Makes some calculations to find out which items the modification the user | ||
* // wants will destroy. Returns a number | ||
* } | ||
* | ||
* function getUserConfirmation(itemsCount) { | ||
* // Return a resolved promise if the user confirms the destruction, | ||
* // and rejects it otherwise | ||
* } | ||
* | ||
* function saveModifications() { | ||
* // Makes ajax to save modifications on the server, returning a | ||
* // promise. | ||
* } | ||
* | ||
* function showNotification() { | ||
* // Notifies that the modification was successful | ||
* } | ||
* | ||
* // Composes the whole process into one function that returns a promise | ||
* var wholeProcess = func.compose(getHowMuchWeWillDestroy, | ||
* getUserConfirmation, | ||
* saveModifications, | ||
* showNotification); | ||
* | ||
* // Which is equivalent to | ||
* var wholeProcess = function(parameter) { | ||
* return fn.call(getHowMuchWeWillDestroy, parameter) | ||
* .then(getUserConfirmation) | ||
* .then(saveModifications) | ||
* .then(showNotification); | ||
* } | ||
* | ||
* @param {Function} f the function to which the arguments will be passed | ||
@@ -203,3 +111,3 @@ * @param {...Function} [funcs] functions that will be composed, in order | ||
args = slice.call(arguments); | ||
firstPromise = _apply(f, thisArg, args); | ||
firstPromise = attempt.apply(thisArg, [f].concat(args)); | ||
@@ -212,8 +120,4 @@ return when.reduce(funcs, function(arg, func) { | ||
}); | ||
})(typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); }); | ||
})( | ||
typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); } | ||
// Boilerplate for AMD and Node | ||
); | ||
@@ -1,2 +0,2 @@ | ||
/** @license MIT License (c) copyright 2010-2013 original author or authors */ | ||
/** @license MIT License (c) copyright 2010-2014 original author or authors */ | ||
@@ -3,0 +3,0 @@ /** |
16
guard.js
@@ -30,9 +30,7 @@ /** @license MIT License (c) copyright 2011-2013 original author or authors */ | ||
return function() { | ||
var self, args; | ||
var self = this; | ||
var args = arguments; | ||
self = this; | ||
args = arguments; | ||
return when(condition(), function(exit) { | ||
return when(f.apply(self, args)).ensure(exit); | ||
return when(f.apply(self, args))['finally'](exit); | ||
}); | ||
@@ -52,7 +50,5 @@ }; | ||
function n(allowed) { | ||
var count, waiting; | ||
var count = 0; | ||
var waiting = []; | ||
count = 0; | ||
waiting = []; | ||
return function enter() { | ||
@@ -69,3 +65,3 @@ return when.promise(function(resolve) { | ||
count = Math.max(count - 1, 0); | ||
if(waiting.length) { | ||
if(waiting.length > 0) { | ||
waiting.shift()(exit); | ||
@@ -72,0 +68,0 @@ } |
96
keys.js
@@ -12,34 +12,11 @@ /** @license MIT License (c) copyright 2011-2013 original author or authors */ | ||
define(function(require) { | ||
var when, promise, keys, eachKey, owns; | ||
when = require('./when'); | ||
promise = when.promise; | ||
var when = require('./when'); | ||
var toPromise = when.resolve; | ||
// Public API | ||
keys = { | ||
all: all, | ||
return { | ||
all: when.lift(all), | ||
map: map | ||
}; | ||
// Safe ownProp | ||
owns = {}.hasOwnProperty; | ||
// Use Object.keys if available, otherwise for..in | ||
eachKey = Object.keys | ||
? function(object, lambda) { | ||
Object.keys(object).forEach(function(key) { | ||
lambda(object[key], key); | ||
}); | ||
} | ||
: function(object, lambda) { | ||
for(var key in object) { | ||
if(owns.call(object, key)) { | ||
lambda(object[key], key); | ||
} | ||
} | ||
}; | ||
return keys; | ||
/** | ||
@@ -53,3 +30,25 @@ * Resolve all the key-value pairs in the supplied object or promise | ||
function all(object) { | ||
return map(object, identity); | ||
return when.promise(function(resolve, reject, notify) { | ||
var results = {}; | ||
var pending = 0; | ||
for(var k in object) { | ||
resolveOne(object[k], k); | ||
} | ||
if(pending === 0) { | ||
resolve(results); | ||
} | ||
function resolveOne(x, k) { | ||
++pending; | ||
toPromise(x).then(function(x) { | ||
results[k] = x; | ||
if(--pending === 0) { | ||
resolve(results); | ||
} | ||
}, reject, notify); | ||
} | ||
}); | ||
} | ||
@@ -61,3 +60,3 @@ | ||
* will be reduced | ||
* @param {function} mapFunc mapping function mapFunc(value) which may | ||
* @param {function} f mapping function mapFunc(value) which may | ||
* return either a promise or a value | ||
@@ -67,37 +66,12 @@ * @returns {Promise} promise for an object with the mapped and fully | ||
*/ | ||
function map(object, mapFunc) { | ||
return when(object, function(object) { | ||
return promise(resolveMap); | ||
function resolveMap(resolve, reject, notify) { | ||
var results, toResolve; | ||
results = {}; | ||
toResolve = 0; | ||
eachKey(object, function(value, key) { | ||
++toResolve; | ||
when(value, mapFunc).then(function(mapped) { | ||
results[key] = mapped; | ||
if(!--toResolve) { | ||
resolve(results); | ||
} | ||
}, reject, notify); | ||
}); | ||
// If there are no keys, resolve immediately | ||
if(!toResolve) { | ||
resolve(results); | ||
} | ||
} | ||
function map(object, f) { | ||
return toPromise(object).then(function(object) { | ||
return all(Object.keys(object).reduce(function(o, k) { | ||
o[k] = toPromise(object[k]).then(f); | ||
return o; | ||
}, {})); | ||
}); | ||
} | ||
function identity(x) { return x; } | ||
}); | ||
})( | ||
typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); } | ||
// Boilerplate for AMD and Node | ||
); | ||
})(typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); }); |
@@ -1,51 +0,21 @@ | ||
/** @license MIT License (c) copyright 2010-2013 original author or authors */ | ||
/** @license MIT License (c) copyright 2010-2014 original author or authors */ | ||
/** @author Brian Cavalier */ | ||
/** @author John Hann */ | ||
/** | ||
* 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 createAggregator, throttleReporter, simpleReporter, aggregator, | ||
formatter, stackFilter, excludeRx, filter, reporter, logger, | ||
rejectionMsg, reasonMsg, filteredFramesMsg, stackJumpMsg, attachPoint; | ||
var PromiseMonitor = require('./PromiseMonitor'); | ||
var ConsoleReporter = require('./ConsoleReporter'); | ||
createAggregator = require('./aggregator'); | ||
throttleReporter = require('./throttledReporter'); | ||
simpleReporter = require('./simpleReporter'); | ||
formatter = require('./simpleFormatter'); | ||
stackFilter = require('./stackFilter'); | ||
logger = require('./logger/consoleGroup'); | ||
var traceFilter = /(node|module|timers)\.js:|when(\/(lib|monitor)\/|\.js)/i; | ||
var promiseMonitor = new PromiseMonitor(new ConsoleReporter(traceFilter)); | ||
rejectionMsg = '=== Unhandled rejection escaped at ==='; | ||
reasonMsg = '=== Caused by reason ==='; | ||
stackJumpMsg = ' --- new call stack ---'; | ||
filteredFramesMsg = ' ...[filtered frames]...'; | ||
excludeRx = /when\.js|(module|node)\.js:\d|when\/monitor\//i; | ||
filter = stackFilter(exclude, mergePromiseFrames); | ||
reporter = simpleReporter(formatter(filter, rejectionMsg, reasonMsg, stackJumpMsg), logger); | ||
aggregator = createAggregator(throttleReporter(200, reporter)); | ||
attachPoint = typeof console !== 'undefined' | ||
? aggregator.publish(console) | ||
: aggregator; | ||
return aggregator; | ||
function mergePromiseFrames(/* frames */) { | ||
return filteredFramesMsg; | ||
if(typeof console !== 'undefined') { | ||
console.promiseMonitor = promiseMonitor; | ||
} | ||
function exclude(line) { | ||
var rx = attachPoint.promiseStackFilter || excludeRx; | ||
return rx.test(line); | ||
} | ||
return promiseMonitor; | ||
}); | ||
}(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(require); })); |
/** @license MIT License (c) copyright 2013 original author or authors */ | ||
/** | ||
* node/function.js | ||
* | ||
* Collection of helpers for interfacing with node-style asynchronous functions | ||
* using promises. | ||
* | ||
* @author brian@hovercraftstudios.com | ||
* @contributor renato.riccieri@gmail.com | ||
* @author Brian Cavalier | ||
*/ | ||
(function(define) { | ||
(function(define) { 'use strict'; | ||
define(function(require) { | ||
var when, slice, setTimer, cjsRequire, vertxSetTimer; | ||
// DEPRECATED: Use when/node instead | ||
return require('../node'); | ||
when = require('../when'); | ||
slice = [].slice; | ||
cjsRequire = require; | ||
try { | ||
vertxSetTimer = cjsRequire('vertx').setTimer; | ||
setTimer = function (f, ms) { return vertxSetTimer(ms, f); }; | ||
} catch(e) { | ||
setTimer = setTimeout; | ||
} | ||
return { | ||
apply: apply, | ||
call: call, | ||
lift: lift, | ||
bind: lift, // DEPRECATED alias for lift | ||
createCallback: createCallback, | ||
bindCallback: bindCallback, | ||
liftCallback: liftCallback | ||
}; | ||
/** | ||
* Takes a node-style async function and calls it immediately (with an optional | ||
* array of arguments or promises for arguments). It returns a promise whose | ||
* resolution depends on whether the async functions calls its callback with the | ||
* conventional error argument or not. | ||
* | ||
* With this it becomes possible to leverage existing APIs while still reaping | ||
* the benefits of promises. | ||
* | ||
* @example | ||
* function onlySmallNumbers(n, callback) { | ||
* if(n < 10) { | ||
* callback(null, n + 10); | ||
* } else { | ||
* callback(new Error("Calculation failed")); | ||
* } | ||
* } | ||
* | ||
* var nodefn = require("when/node/function"); | ||
* | ||
* // Logs '15' | ||
* nodefn.apply(onlySmallNumbers, [5]).then(console.log, console.error); | ||
* | ||
* // Logs 'Calculation failed' | ||
* nodefn.apply(onlySmallNumbers, [15]).then(console.log, console.error); | ||
* | ||
* @param {function} func node-style function that will be called | ||
* @param {Array} [args] array of arguments to func | ||
* @returns {Promise} promise for the value func passes to its callback | ||
*/ | ||
function apply(func, args) { | ||
return _apply(func, this, args); | ||
} | ||
/** | ||
* Apply helper that allows specifying thisArg | ||
* @private | ||
*/ | ||
function _apply(func, thisArg, args) { | ||
return when.all(args || []).then(function(resolvedArgs) { | ||
var d = when.defer(); | ||
var callback = createCallback(d.resolver); | ||
func.apply(thisArg, resolvedArgs.concat(callback)); | ||
return d.promise; | ||
}); | ||
} | ||
/** | ||
* Has the same behavior that {@link apply} has, with the difference that the | ||
* arguments to the function are provided individually, while {@link apply} accepts | ||
* a single array. | ||
* | ||
* @example | ||
* function sumSmallNumbers(x, y, callback) { | ||
* var result = x + y; | ||
* if(result < 10) { | ||
* callback(null, result); | ||
* } else { | ||
* callback(new Error("Calculation failed")); | ||
* } | ||
* } | ||
* | ||
* // Logs '5' | ||
* nodefn.call(sumSmallNumbers, 2, 3).then(console.log, console.error); | ||
* | ||
* // Logs 'Calculation failed' | ||
* nodefn.call(sumSmallNumbers, 5, 10).then(console.log, console.error); | ||
* | ||
* @param {function} func node-style function that will be called | ||
* @param {...*} [args] arguments that will be forwarded to the function | ||
* @returns {Promise} promise for the value func passes to its callback | ||
*/ | ||
function call(func /*, args... */) { | ||
return _apply(func, this, slice.call(arguments, 1)); | ||
} | ||
/** | ||
* Takes a node-style function and returns new function that wraps the | ||
* original and, instead of taking a callback, returns a promise. Also, it | ||
* knows how to handle promises given as arguments, waiting for their | ||
* resolution before executing. | ||
* | ||
* Upon execution, the orginal function is executed as well. If it passes | ||
* a truthy value as the first argument to the callback, it will be | ||
* interpreted as an error condition, and the promise will be rejected | ||
* with it. Otherwise, the call is considered a resolution, and the promise | ||
* is resolved with the callback's second argument. | ||
* | ||
* @example | ||
* var fs = require("fs"), nodefn = require("when/node/function"); | ||
* | ||
* var promiseRead = nodefn.lift(fs.readFile); | ||
* | ||
* // The promise is resolved with the contents of the file if everything | ||
* // goes ok | ||
* promiseRead('exists.txt').then(console.log, console.error); | ||
* | ||
* // And will be rejected if something doesn't work out | ||
* // (e.g. the files does not exist) | ||
* promiseRead('doesnt_exist.txt').then(console.log, console.error); | ||
* | ||
* | ||
* @param {Function} func node-style function to be bound | ||
* @param {...*} [args] arguments to be prepended for the new function | ||
* @returns {Function} a promise-returning function | ||
*/ | ||
function lift(func /*, args... */) { | ||
var args = slice.call(arguments, 1); | ||
return function() { | ||
return _apply(func, this, args.concat(slice.call(arguments))); | ||
}; | ||
} | ||
/** | ||
* Takes an object that responds to the resolver interface, and returns | ||
* a function that will resolve or reject it depending on how it is called. | ||
* | ||
* @example | ||
* function callbackTakingFunction(callback) { | ||
* if(somethingWrongHappened) { | ||
* callback(error); | ||
* } else { | ||
* callback(null, interestingValue); | ||
* } | ||
* } | ||
* | ||
* var when = require('when'), nodefn = require('when/node/function'); | ||
* | ||
* var deferred = when.defer(); | ||
* callbackTakingFunction(nodefn.createCallback(deferred.resolver)); | ||
* | ||
* deferred.promise.then(function(interestingValue) { | ||
* // Use interestingValue | ||
* }); | ||
* | ||
* @param {Resolver} resolver that will be 'attached' to the callback | ||
* @returns {Function} a node-style callback function | ||
*/ | ||
function createCallback(resolver) { | ||
return function(err, value) { | ||
if(err) { | ||
resolver.reject(err); | ||
} else if(arguments.length > 2) { | ||
resolver.resolve(slice.call(arguments, 1)); | ||
} else { | ||
resolver.resolve(value); | ||
} | ||
}; | ||
} | ||
/** | ||
* Attaches a node-style callback to a promise, ensuring the callback is | ||
* called for either fulfillment or rejection. Returns a promise with the same | ||
* state as the passed-in promise. | ||
* | ||
* @example | ||
* var deferred = when.defer(); | ||
* | ||
* function callback(err, value) { | ||
* // Handle err or use value | ||
* } | ||
* | ||
* bindCallback(deferred.promise, callback); | ||
* | ||
* deferred.resolve('interesting value'); | ||
* | ||
* @param {Promise} promise The promise to be attached to. | ||
* @param {Function} callback The node-style callback to attach. | ||
* @returns {Promise} A promise with the same state as the passed-in promise. | ||
*/ | ||
function bindCallback(promise, callback) { | ||
promise = when(promise); | ||
if (callback) { | ||
promise.then(success, wrapped); | ||
} | ||
return promise; | ||
function success(value) { | ||
wrapped(null, value); | ||
} | ||
function wrapped(err, value) { | ||
setTimer(function () { | ||
callback(err, value); | ||
}, 0); | ||
} | ||
} | ||
/** | ||
* Takes a node-style callback and returns new function that accepts a | ||
* promise, calling the original callback when the promise is either | ||
* fulfilled or rejected with the appropriate arguments. | ||
* | ||
* @example | ||
* var deferred = when.defer(); | ||
* | ||
* function callback(err, value) { | ||
* // Handle err or use value | ||
* } | ||
* | ||
* var wrapped = liftCallback(callback); | ||
* | ||
* // `wrapped` can now be passed around at will | ||
* wrapped(deferred.promise); | ||
* | ||
* deferred.resolve('interesting value'); | ||
* | ||
* @param {Function} callback The node-style callback to wrap. | ||
* @returns {Function} The lifted, promise-accepting function. | ||
*/ | ||
function liftCallback(callback) { | ||
return function(promise) { | ||
return bindCallback(promise, callback); | ||
}; | ||
} | ||
}); | ||
})( | ||
typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); } | ||
// Boilerplate for AMD and Node | ||
); | ||
}(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(require); })); |
{ | ||
"name": "when", | ||
"version": "2.8.0", | ||
"version": "3.0.0", | ||
"description": "A lightweight Promises/A+ and when() implementation, plus other async goodies.", | ||
"keywords": ["Promises/A+", "promises-aplus", "promise", "promises", "deferred", "deferreds", "when", "async", "asynchronous", "cujo", "ender"], | ||
"keywords": [ | ||
"cujo", | ||
"Promises/A+", | ||
"promises-aplus", | ||
"promise", | ||
"promises", | ||
"deferred", | ||
"deferreds", | ||
"when", | ||
"async", | ||
"asynchronous", | ||
"ender" | ||
], | ||
"homepage": "http://cujojs.com", | ||
@@ -42,3 +54,4 @@ "licenses": [ | ||
"devDependencies": { | ||
"curl": "https://github.com/cujojs/curl/tarball/0.7.3", | ||
"curl": "git://github.com/cujojs/curl", | ||
"poly": "git://github.com/cujojs/poly", | ||
"test-support": "~0.3", | ||
@@ -51,3 +64,3 @@ "promises-aplus-tests": "~2", | ||
"main": "when", | ||
"ender": { "files": ["*.js", "node/*.js", "unfold/*.js", "monitor/*.js"] }, | ||
"ender": { "files": ["*.js", "lib/*.js", "node/*.js", "unfold/*.js", "monitor/*.js"] }, | ||
"directories": { | ||
@@ -58,9 +71,10 @@ "test": "test" | ||
"test": "jshint . && buster test -e node -r specification && promises-aplus-tests test/promises-aplus-adapter.js --reporter spec", | ||
"ci": "npm test && sauceme", | ||
"ci": "npm test && sauceme -b test/browsers.json", | ||
"tunnel": "sauceme -m", | ||
"start": "buster static -e browser", | ||
"benchmark": "node benchmark/promise && node benchmark/map", | ||
"browserify": "browserify -s when build/when.browserify.js -o build/when.js", | ||
"browserify-debug": "browserify -s when build/when.browserify-debug.js -o build/when.js" | ||
"browserify-es6": "browserify -s Promise es6-shim/Promise.browserify-es6.js --no-detect-globals -o es6-shim/Promise.js", | ||
"browserify": "browserify -s when build/when.browserify.js --no-detect-globals -o build/when.js", | ||
"browserify-debug": "browserify -s when build/when.browserify-debug.js --no-detect-globals -o build/when.js" | ||
} | ||
} |
@@ -16,7 +16,6 @@ /** @license MIT License (c) copyright 2011-2013 original author or authors */ | ||
var when, slice; | ||
var when = require('./when'); | ||
var all = when.Promise.all; | ||
var slice = Array.prototype.slice; | ||
when = require('./when'); | ||
slice = Array.prototype.slice; | ||
/** | ||
@@ -31,5 +30,5 @@ * Run array of tasks in parallel | ||
return function parallel(tasks /*, args... */) { | ||
return when.all(slice.call(arguments, 1)).then(function(args) { | ||
return all(slice.call(arguments, 1)).then(function(args) { | ||
return when.map(tasks, function(task) { | ||
return task.apply(null, args); | ||
return task.apply(void 0, args); | ||
}); | ||
@@ -40,7 +39,4 @@ }); | ||
}); | ||
})( | ||
typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); } | ||
// Boilerplate for AMD and Node | ||
); | ||
})(typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); }); | ||
@@ -17,7 +17,6 @@ /** @license MIT License (c) copyright 2011-2013 original author or authors */ | ||
var when, slice; | ||
var when = require('./when'); | ||
var all = when.Promise.all; | ||
var slice = Array.prototype.slice; | ||
when = require('./when'); | ||
slice = Array.prototype.slice; | ||
/** | ||
@@ -42,3 +41,3 @@ * Run array of tasks in a pipeline where the next | ||
return when.all(slice.call(arguments, 1)).then(function(args) { | ||
return all(slice.call(arguments, 1)).then(function(args) { | ||
return when.reduce(tasks, function(arg, task) { | ||
@@ -51,7 +50,4 @@ return runTask(arg, task); | ||
}); | ||
})( | ||
typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); } | ||
// Boilerplate for AMD and Node | ||
); | ||
})(typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); }); | ||
33
poll.js
@@ -11,12 +11,10 @@ /** @license MIT License (c) copyright 2012-2013 original author or authors */ | ||
(function (define) { | ||
'use strict'; | ||
(function (define) { 'use strict'; | ||
define(function(require) { | ||
var when, cancelable, delay, fn, undef; | ||
var when, attempt, cancelable; | ||
when = require('./when'); | ||
attempt = when['try']; | ||
cancelable = require('./cancelable'); | ||
delay = require('./delay'); | ||
fn = require('./function'); | ||
@@ -74,3 +72,3 @@ /** | ||
interval = (function (interval) { | ||
return function () { return delay(interval); }; | ||
return function () { return when().delay(interval); }; | ||
})(interval); | ||
@@ -84,4 +82,4 @@ } | ||
function schedule(result) { | ||
fn.apply(interval).then(vote, reject); | ||
if (result !== undef) { | ||
attempt(interval).then(vote, reject); | ||
if (result !== void 0) { | ||
deferred.notify(result); | ||
@@ -108,4 +106,3 @@ } | ||
schedule(); | ||
} | ||
else { | ||
} else { | ||
// if work() is blocking, vote will also block | ||
@@ -116,3 +113,3 @@ vote(); | ||
// make the promise cancelable | ||
deferred.promise = beget(deferred.promise); | ||
deferred.promise = Object.create(deferred.promise); | ||
deferred.promise.cancel = deferred.cancel; | ||
@@ -123,15 +120,3 @@ | ||
function F() {} | ||
function beget(p) { | ||
F.prototype = p; | ||
var newPromise = new F(); | ||
F.prototype = null; | ||
return newPromise; | ||
} | ||
}); | ||
})( | ||
typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); } | ||
// Boilerplate for AMD and Node | ||
); | ||
})(typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); }); |
@@ -5,17 +5,18 @@ <a href="http://promises-aplus.github.com/promises-spec"><img src="http://promises-aplus.github.com/promises-spec/assets/logo-small.png" alt="Promises/A+ logo" align="right" /></a> | ||
# when.js | ||
when.js | ||
======= | ||
When.js is cujoJS's lightweight [Promises/A+](http://promises-aplus.github.com/promises-spec) and `when()` implementation that powers the async core of [wire.js](https://github.com/cujojs/wire), cujoJS's IOC Container. It features: | ||
When.js is a rock solid, battle-tested [Promises/A+](http://promises-aplus.github.com/promises-spec) and `when()` implementation, including a complete [ES6 Promise shim](docs/es6-promise-shim.md). It's a powerful combination of small size, high performance, and rich features: | ||
* A rock solid, battle-tested Promise implementation | ||
* Resolving, settling, mapping, and reducing arrays of promises | ||
* Executing tasks in parallel and sequence | ||
* Transforming Node-style and other callback-based APIs into promise-based APIs | ||
* Resolve arrays and hashes of promises, as well as infinite promise sequences | ||
* Execute tasks in parallel or sequentially | ||
* Transform Node-style and other callback-based APIs into promise-based APIs | ||
It passes the [Promises/A+ Test Suite](https://github.com/promises-aplus/promises-tests), is [very fast](https://github.com/cujojs/promise-perf-tests#test-results) and compact, and has no external dependencies. | ||
When.js is one of the many stand-alone components of [cujoJS](http://cujojs.com), the JavaScript Architectural Toolkit. | ||
Check it out: | ||
- [What's new](CHANGES.md) | ||
- [API docs](docs/api.md#api) | ||
- [Examples](https://github.com/cujojs/when/wiki/Examples) | ||
- [More info on the wiki](https://github.com/cujojs/when/wiki) | ||
- Read more about how [promises simplify async programming](http://know.cujojs.com/tutorials/async/simplifying-async-with-promises) | ||
@@ -27,8 +28,12 @@ Installation | ||
Availble as `when` through [bower](http://bower.io) and [yeoman](https://github.com/yeoman/yo), or just clone the repo and load `when.js` from the root. When.js is AMD-compatible out of the box, so no need for shims. | ||
Availble as `when` through [bower](http://bower.io), or just clone the repo and load `when.js` from the root. | ||
``` | ||
bower install --save when | ||
``` | ||
#### CommonJS/Node | ||
``` | ||
npm install when | ||
npm install --save when | ||
``` | ||
@@ -89,9 +94,6 @@ | ||
- For more examples, see [examples »](https://github.com/cujojs/when/wiki/Examples) | ||
- For the full documentation see [api docs »](docs/api.md#api) | ||
License | ||
------- | ||
Licensed under MIT. [See the license here »](LICENSE.txt) | ||
Licensed under MIT. [Full license here »](LICENSE.txt) | ||
@@ -98,0 +100,0 @@ Contributing |
@@ -16,7 +16,6 @@ /** @license MIT License (c) copyright 2011-2013 original author or authors */ | ||
var when, slice; | ||
var when = require('./when'); | ||
var all = when.Promise.all; | ||
var slice = Array.prototype.slice; | ||
when = require('./when'); | ||
slice = Array.prototype.slice; | ||
/** | ||
@@ -33,5 +32,5 @@ * Run array of tasks in sequence with no overlap | ||
return when.all(slice.call(arguments, 1)).then(function(args) { | ||
return all(slice.call(arguments, 1)).then(function(args) { | ||
return when.reduce(tasks, function(results, task) { | ||
return when(task.apply(null, args), addResult); | ||
return when(task.apply(void 0, args), addResult); | ||
}, results); | ||
@@ -47,7 +46,4 @@ }); | ||
}); | ||
})( | ||
typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); } | ||
// Boilerplate for AMD and Node | ||
); | ||
})(typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); }); | ||
@@ -15,58 +15,14 @@ /** @license MIT License (c) copyright 2011-2013 original author or authors */ | ||
define(function(require) { | ||
/*global setTimeout,clearTimeout*/ | ||
var when, setTimer, cancelTimer, cjsRequire, vertx; | ||
when = require('./when'); | ||
cjsRequire = require; | ||
var resolve = require('./when').resolve; | ||
try { | ||
vertx = cjsRequire('vertx'); | ||
setTimer = function (f, ms) { return vertx.setTimer(ms, f); }; | ||
cancelTimer = vertx.cancelTimer; | ||
} catch (e) { | ||
setTimer = setTimeout; | ||
cancelTimer = clearTimeout; | ||
} | ||
/** | ||
* Returns a new promise that will automatically reject after msec if | ||
* the supplied trigger doesn't resolve or reject before that. | ||
* | ||
* @param {number} msec timeout in milliseconds | ||
* @param {*|Promise} trigger any promise or value that should trigger the | ||
* returned promise to resolve or reject before the msec timeout | ||
* @returns {Promise} promise that will timeout after msec, or be | ||
* equivalent to trigger if resolved/rejected before msec | ||
* @deprecated Use when(trigger).timeout(ms) | ||
*/ | ||
return function timeout(msec, trigger) { | ||
// Support reversed, deprecated argument ordering | ||
if(typeof trigger === 'number') { | ||
var tmp = trigger; | ||
trigger = msec; | ||
msec = tmp; | ||
} | ||
return when.promise(function(resolve, reject, notify) { | ||
var timeoutRef = setTimer(function onTimeout() { | ||
reject(new Error('timed out after ' + msec + 'ms')); | ||
}, msec); | ||
when(trigger, | ||
function onFulfill(value) { | ||
cancelTimer(timeoutRef); | ||
resolve(value); | ||
}, | ||
function onReject(reason) { | ||
cancelTimer(timeoutRef); | ||
reject(reason); | ||
}, | ||
notify | ||
); | ||
}); | ||
return resolve(trigger).timeout(msec); | ||
}; | ||
}); | ||
})( | ||
typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); }); | ||
})(typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); }); | ||
@@ -10,33 +10,9 @@ /** @license MIT License (c) copyright B Cavalier & J Hann */ | ||
var when = require('./when'); | ||
/** | ||
* Anamorphic unfold/map that generates 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 generator | ||
* @param seed {*|Promise} any value or promise | ||
* @return {Promise} the result of the unfold | ||
* @deprecated Use when.unfold | ||
*/ | ||
return function unfold(unspool, condition, handler, seed) { | ||
return when(seed, function(seed) { | ||
return require('./when').unfold; | ||
return when(condition(seed), function(done) { | ||
return done ? seed : when.resolve(unspool(seed)).spread(next); | ||
}); | ||
function next(item, newSeed) { | ||
return when(handler(item), function() { | ||
return unfold(unspool, condition, handler, newSeed); | ||
}); | ||
} | ||
}); | ||
}; | ||
}); | ||
})(typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); } ); | ||
/** @license MIT License (c) copyright B Cavalier & J Hann */ | ||
/** | ||
* unfold | ||
* @author: brian@hovercraftstudios.com | ||
*/ | ||
(function(define) { | ||
define(function(require) { | ||
var when, unfold; | ||
var unfold = require('../when').unfold; | ||
when = require('../when'); | ||
unfold = require('../unfold'); | ||
/** | ||
* @deprecated | ||
* Given a seed and generator, produces an Array. Effectively the | ||
@@ -37,6 +31,3 @@ * dual (opposite) of when.reduce() | ||
}); | ||
})( | ||
typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); } | ||
// Boilerplate for AMD and Node | ||
); | ||
})(typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); }); | ||
954
when.js
@@ -1,13 +0,9 @@ | ||
/** @license MIT License (c) copyright 2011-2013 original author or authors */ | ||
/** @license MIT License (c) copyright 2010-2014 original author or authors */ | ||
/** | ||
* A lightweight CommonJS Promises/A and when() implementation | ||
* when is part of the cujo.js family of libraries (http://cujojs.com/) | ||
* | ||
* Licensed under the MIT License at: | ||
* http://www.opensource.org/licenses/mit-license.php | ||
* | ||
* when is part of the cujoJS family of libraries (http://cujojs.com/) | ||
* @author Brian Cavalier | ||
* @author John Hann | ||
* @version 2.8.0 | ||
* @version 3.0.0 | ||
*/ | ||
@@ -17,41 +13,68 @@ (function(define) { 'use strict'; | ||
var timer = require('./lib/timer'); | ||
var timed = require('./lib/timed'); | ||
var array = require('./lib/array'); | ||
var flow = require('./lib/flow'); | ||
var inspect = require('./lib/inspect'); | ||
var generate = require('./lib/iterate'); | ||
var progress = require('./lib/progress'); | ||
var withThis = require('./lib/with'); | ||
var Promise = require('./lib/Promise'); | ||
Promise = [array, flow, generate, progress, inspect, withThis] | ||
.reduceRight(function(Promise, feature) { | ||
return feature(Promise); | ||
}, timed(timer.set, timer.clear, Promise)); | ||
var resolve = Promise.resolve; | ||
var slice = Array.prototype.slice; | ||
// Public API | ||
when.promise = promise; // Create a pending promise | ||
when.resolve = resolve; // Create a resolved promise | ||
when.reject = reject; // Create a rejected promise | ||
when.defer = defer; // Create a {promise, resolver} pair | ||
when.promise = promise; // Create a pending promise | ||
when.resolve = Promise.resolve; // Create a resolved promise | ||
when.reject = Promise.reject; // Create a rejected promise | ||
when.join = join; // Join 2 or more promises | ||
when.lift = lift; // lift a function to return promises | ||
when['try'] = tryCall; // call a function and return a promise | ||
when.attempt = tryCall; // alias for when.try | ||
when.all = all; // Resolve a list of promises | ||
when.map = map; // Array.map() for promises | ||
when.reduce = reduce; // Array.reduce() for promises | ||
when.settle = settle; // Settle a list of promises | ||
when.iterate = Promise.iterate; // Generate a stream of promises | ||
when.unfold = Promise.unfold; // Generate a stream of promises | ||
when.any = any; // One-winner race | ||
when.some = some; // Multi-winner race | ||
when.join = join; // Join 2 or more promises | ||
when.isPromise = isPromiseLike; // DEPRECATED: use isPromiseLike | ||
when.isPromiseLike = isPromiseLike; // Is something promise-like, aka thenable | ||
when.all = all; // Resolve a list of promises | ||
when.settle = settle; // Settle a list of promises | ||
when.any = lift(Promise.any); // One-winner race | ||
when.some = lift(Promise.some); // Multi-winner race | ||
when.map = map; // Array.map() for promises | ||
when.reduce = reduce; // Array.reduce() for promises | ||
when.reduceRight = reduceRight; // Array.reduceRight() for promises | ||
when.isPromiseLike = isPromiseLike; // Is something promise-like, aka thenable | ||
when.Promise = Promise; // Promise constructor | ||
when.defer = defer; // Create a {promise, resolve, reject} tuple | ||
/** | ||
* Register an observer for a promise or immediate value. | ||
* When x, which may be a promise, thenable, or non-promise value, | ||
* | ||
* @param {*} promiseOrValue | ||
* @param {function?} [onFulfilled] callback to be called when promiseOrValue is | ||
* @param {*} x | ||
* @param {function?} onFulfilled callback to be called when x is | ||
* successfully fulfilled. If promiseOrValue is an immediate value, callback | ||
* will be invoked immediately. | ||
* @param {function?} [onRejected] callback to be called when promiseOrValue is | ||
* @param {function?} onRejected callback to be called when x is | ||
* rejected. | ||
* @param {function?} [onProgress] callback to be called when progress updates | ||
* are issued for promiseOrValue. | ||
* @returns {Promise} a new {@link Promise} that will complete with the return | ||
* @param {function?} onProgress callback to be called when progress updates | ||
* are issued for x. | ||
* @returns {Promise} a new promise that will fulfill with the return | ||
* value of callback or errback or the completion value of promiseOrValue if | ||
* callback and/or errback is not supplied. | ||
*/ | ||
function when(promiseOrValue, onFulfilled, onRejected, onProgress) { | ||
// Get a trusted promise for the input promiseOrValue, and then | ||
// register promise handlers | ||
return cast(promiseOrValue).then(onFulfilled, onRejected, onProgress); | ||
function when(x, onFulfilled, onRejected, onProgress) { | ||
var p = resolve(x); | ||
return arguments.length < 2 ? p : p.then(onFulfilled, onRejected, onProgress); | ||
} | ||
@@ -65,225 +88,35 @@ | ||
function promise(resolver) { | ||
return new Promise(resolver, | ||
monitorApi.PromiseStatus && monitorApi.PromiseStatus()); | ||
return new Promise(resolver); | ||
} | ||
/** | ||
* Trusted Promise constructor. A Promise created from this constructor is | ||
* a trusted when.js promise. Any other duck-typed promise is considered | ||
* untrusted. | ||
* @constructor | ||
* @returns {Promise} promise whose fate is determine by resolver | ||
* @name Promise | ||
* Lift the supplied function, creating a version of f that returns | ||
* promises, and accepts promises as arguments. | ||
* @param {function} f | ||
* @returns {Function} version of f that returns promises | ||
*/ | ||
function Promise(resolver, status) { | ||
var self, value, consumers = []; | ||
self = this; | ||
this._status = status; | ||
this.inspect = inspect; | ||
this._when = _when; | ||
// Call the provider resolver to seal the promise's fate | ||
try { | ||
resolver(promiseResolve, promiseReject, promiseNotify); | ||
} catch(e) { | ||
promiseReject(e); | ||
} | ||
/** | ||
* Returns a snapshot of this promise's current status at the instant of call | ||
* @returns {{state:String}} | ||
*/ | ||
function inspect() { | ||
return value ? value.inspect() : toPendingState(); | ||
} | ||
/** | ||
* Private message delivery. Queues and delivers messages to | ||
* the promise's ultimate fulfillment value or rejection reason. | ||
* @private | ||
*/ | ||
function _when(resolve, notify, onFulfilled, onRejected, onProgress) { | ||
consumers ? consumers.push(deliver) : enqueue(function() { deliver(value); }); | ||
function deliver(p) { | ||
p._when(resolve, notify, onFulfilled, onRejected, onProgress); | ||
} | ||
} | ||
/** | ||
* Transition from pre-resolution state to post-resolution state, notifying | ||
* all listeners of the ultimate fulfillment or rejection | ||
* @param {*} val resolution value | ||
*/ | ||
function promiseResolve(val) { | ||
if(!consumers) { | ||
return; | ||
} | ||
var queue = consumers; | ||
consumers = undef; | ||
value = coerce(self, val); | ||
enqueue(function () { | ||
if(status) { | ||
updateStatus(value, status); | ||
} | ||
runHandlers(queue, value); | ||
}); | ||
} | ||
/** | ||
* Reject this promise with the supplied reason, which will be used verbatim. | ||
* @param {*} reason reason for the rejection | ||
*/ | ||
function promiseReject(reason) { | ||
promiseResolve(new RejectedPromise(reason)); | ||
} | ||
/** | ||
* Issue a progress event, notifying all progress listeners | ||
* @param {*} update progress event payload to pass to all listeners | ||
*/ | ||
function promiseNotify(update) { | ||
if(consumers) { | ||
var queue = consumers; | ||
enqueue(function () { | ||
runHandlers(queue, new ProgressingPromise(update)); | ||
}); | ||
} | ||
} | ||
function lift(f) { | ||
return function() { | ||
return _apply(f, this, slice.call(arguments)); | ||
}; | ||
} | ||
promisePrototype = Promise.prototype; | ||
/** | ||
* Register handlers for this promise. | ||
* @param [onFulfilled] {Function} fulfillment handler | ||
* @param [onRejected] {Function} rejection handler | ||
* @param [onProgress] {Function} progress handler | ||
* @return {Promise} new Promise | ||
*/ | ||
promisePrototype.then = function(onFulfilled, onRejected, onProgress) { | ||
var self = this; | ||
return new Promise(function(resolve, reject, notify) { | ||
self._when(resolve, notify, onFulfilled, onRejected, onProgress); | ||
}, this._status && this._status.observed()); | ||
}; | ||
/** | ||
* Register a rejection handler. Shortcut for .then(undefined, onRejected) | ||
* @param {function?} onRejected | ||
* @return {Promise} | ||
*/ | ||
promisePrototype['catch'] = promisePrototype.otherwise = function(onRejected) { | ||
return this.then(undef, onRejected); | ||
}; | ||
/** | ||
* 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} onFulfilledOrRejected handler to be called regardless of | ||
* fulfillment or rejection | ||
* Call f in a future turn, with the supplied args, and return a promise | ||
* for the result. | ||
* @param {function} f | ||
* @returns {Promise} | ||
*/ | ||
promisePrototype['finally'] = promisePrototype.ensure = function(onFulfilledOrRejected) { | ||
return typeof onFulfilledOrRejected === 'function' | ||
? this.then(injectHandler, injectHandler)['yield'](this) | ||
: this; | ||
function injectHandler() { | ||
return resolve(onFulfilledOrRejected()); | ||
} | ||
}; | ||
/** | ||
* Terminate a promise chain by handling the ultimate fulfillment value or | ||
* rejection reason, and assuming responsibility for all errors. if an | ||
* error propagates out of handleResult 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?} handleResult | ||
* @param {function?} handleError | ||
* @returns {undefined} | ||
*/ | ||
promisePrototype.done = function(handleResult, handleError) { | ||
this.then(handleResult, handleError)['catch'](crash); | ||
}; | ||
/** | ||
* 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. | ||
*/ | ||
promisePrototype['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} | ||
*/ | ||
promisePrototype.tap = function(onFulfilledSideEffect) { | ||
return this.then(onFulfilledSideEffect)['yield'](this); | ||
}; | ||
/** | ||
* Assumes that this promise will fulfill with an array, and arranges | ||
* for the onFulfilled to be called with the array as its argument list | ||
* i.e. onFulfilled.apply(undefined, array). | ||
* @param {function} onFulfilled function to receive spread arguments | ||
* @return {Promise} | ||
*/ | ||
promisePrototype.spread = function(onFulfilled) { | ||
return this.then(function(array) { | ||
// array may contain promises, so resolve its contents. | ||
return all(array, function(array) { | ||
return onFulfilled.apply(undef, array); | ||
}); | ||
}); | ||
}; | ||
/** | ||
* Shortcut for .then(onFulfilledOrRejected, onFulfilledOrRejected) | ||
* @deprecated | ||
*/ | ||
promisePrototype.always = function(onFulfilledOrRejected, onProgress) { | ||
return this.then(onFulfilledOrRejected, onFulfilledOrRejected, onProgress); | ||
}; | ||
/** | ||
* Casts x to a trusted promise. If x is already a trusted promise, it is | ||
* returned, otherwise a new trusted Promise which follows x is returned. | ||
* @param {*} x | ||
* @returns {Promise} | ||
*/ | ||
function cast(x) { | ||
return x instanceof Promise ? x : resolve(x); | ||
function tryCall(f /*, args... */) { | ||
/*jshint validthis:true */ | ||
return _apply(f, this, slice.call(arguments, 1)); | ||
} | ||
/** | ||
* Returns a resolved promise. The returned promise will be | ||
* - fulfilled with promiseOrValue if it is a value, or | ||
* - if promiseOrValue is a promise | ||
* - fulfilled with promiseOrValue's value after it is fulfilled | ||
* - rejected with promiseOrValue's reason after it is rejected | ||
* In contract to cast(x), this always creates a new Promise | ||
* @param {*} x | ||
* @return {Promise} | ||
* try/lift helper that allows specifying thisArg | ||
* @private | ||
*/ | ||
function resolve(x) { | ||
return promise(function(resolve) { | ||
resolve(x); | ||
function _apply(func, thisArg, args) { | ||
return Promise.all(args).then(function(args) { | ||
return func.apply(thisArg, args); | ||
}); | ||
@@ -293,223 +126,25 @@ } | ||
/** | ||
* Returns a rejected promise for the supplied promiseOrValue. The returned | ||
* promise will be rejected with: | ||
* - promiseOrValue, if it is a value, or | ||
* - if promiseOrValue is a promise | ||
* - promiseOrValue's value after it is fulfilled | ||
* - promiseOrValue's reason after it is rejected | ||
* @deprecated The behavior of when.reject in 3.0 will be to reject | ||
* with x VERBATIM | ||
* @param {*} x the rejected value of the returned promise | ||
* @return {Promise} rejected promise | ||
*/ | ||
function reject(x) { | ||
return when(x, function(e) { | ||
return new RejectedPromise(e); | ||
}); | ||
} | ||
/** | ||
* Creates a {promise, resolver} pair, either or both of which | ||
* may be given out safely to consumers. | ||
* The resolver has resolve, reject, and progress. The promise | ||
* has then plus extended promise API. | ||
* | ||
* @return {{ | ||
* promise: Promise, | ||
* resolve: function:Promise, | ||
* reject: function:Promise, | ||
* notify: function:Promise | ||
* resolver: { | ||
* resolve: function:Promise, | ||
* reject: function:Promise, | ||
* notify: function:Promise | ||
* }}} | ||
* @return {{promise: Promise, resolve: function, reject: function, notify: function}} | ||
*/ | ||
function defer() { | ||
var deferred, pending, resolved; | ||
// Optimize object shape | ||
deferred = { | ||
promise: undef, resolve: undef, reject: undef, notify: undef, | ||
resolver: { resolve: undef, reject: undef, notify: undef } | ||
}; | ||
deferred.promise = pending = promise(makeDeferred); | ||
return deferred; | ||
function makeDeferred(resolvePending, rejectPending, notifyPending) { | ||
deferred.resolve = deferred.resolver.resolve = function(value) { | ||
if(resolved) { | ||
return resolve(value); | ||
} | ||
resolved = true; | ||
resolvePending(value); | ||
return pending; | ||
}; | ||
deferred.reject = deferred.resolver.reject = function(reason) { | ||
if(resolved) { | ||
return resolve(new RejectedPromise(reason)); | ||
} | ||
resolved = true; | ||
rejectPending(reason); | ||
return pending; | ||
}; | ||
deferred.notify = deferred.resolver.notify = function(update) { | ||
notifyPending(update); | ||
return update; | ||
}; | ||
} | ||
return new Deferred(); | ||
} | ||
/** | ||
* Run a queue of functions as quickly as possible, passing | ||
* value to each. | ||
*/ | ||
function runHandlers(queue, value) { | ||
for (var i = 0; i < queue.length; i++) { | ||
queue[i](value); | ||
} | ||
} | ||
function Deferred() { | ||
var p = Promise._defer(); | ||
/** | ||
* Coerces x to a trusted Promise | ||
* @param {*} x thing to coerce | ||
* @returns {*} Guaranteed to return a trusted Promise. If x | ||
* is trusted, returns x, otherwise, returns a new, trusted, already-resolved | ||
* Promise whose resolution value is: | ||
* * the resolution value of x if it's a foreign promise, or | ||
* * x if it's a value | ||
*/ | ||
function coerce(self, x) { | ||
if (x === self) { | ||
return new RejectedPromise(new TypeError()); | ||
} | ||
function resolve(x) { p._handler.resolve(x); } | ||
function reject(x) { p._handler.reject(x); } | ||
function notify(x) { p._handler.notify(x); } | ||
if (x instanceof Promise) { | ||
return x; | ||
} | ||
try { | ||
var untrustedThen = x === Object(x) && x.then; | ||
return typeof untrustedThen === 'function' | ||
? assimilate(untrustedThen, x) | ||
: new FulfilledPromise(x); | ||
} catch(e) { | ||
return new RejectedPromise(e); | ||
} | ||
this.promise = p; | ||
this.resolve = resolve; | ||
this.reject = reject; | ||
this.notify = notify; | ||
this.resolver = { resolve: resolve, reject: reject, notify: notify }; | ||
} | ||
/** | ||
* Safely assimilates a foreign thenable by wrapping it in a trusted promise | ||
* @param {function} untrustedThen x's then() method | ||
* @param {object|function} x thenable | ||
* @returns {Promise} | ||
*/ | ||
function assimilate(untrustedThen, x) { | ||
return promise(function (resolve, reject) { | ||
enqueue(function() { | ||
try { | ||
fcall(untrustedThen, x, resolve, reject); | ||
} catch(e) { | ||
reject(e); | ||
} | ||
}); | ||
}); | ||
} | ||
makePromisePrototype = Object.create || | ||
function(o) { | ||
function PromisePrototype() {} | ||
PromisePrototype.prototype = o; | ||
return new PromisePrototype(); | ||
}; | ||
/** | ||
* Creates a fulfilled, local promise as a proxy for a value | ||
* NOTE: must never be exposed | ||
* @private | ||
* @param {*} value fulfillment value | ||
* @returns {Promise} | ||
*/ | ||
function FulfilledPromise(value) { | ||
this.value = value; | ||
} | ||
FulfilledPromise.prototype = makePromisePrototype(promisePrototype); | ||
FulfilledPromise.prototype.inspect = function() { | ||
return toFulfilledState(this.value); | ||
}; | ||
FulfilledPromise.prototype._when = function(resolve, _, onFulfilled) { | ||
try { | ||
resolve(typeof onFulfilled === 'function' ? onFulfilled(this.value) : this.value); | ||
} catch(e) { | ||
resolve(new RejectedPromise(e)); | ||
} | ||
}; | ||
/** | ||
* Creates a rejected, local promise as a proxy for a value | ||
* NOTE: must never be exposed | ||
* @private | ||
* @param {*} reason rejection reason | ||
* @returns {Promise} | ||
*/ | ||
function RejectedPromise(reason) { | ||
this.value = reason; | ||
} | ||
RejectedPromise.prototype = makePromisePrototype(promisePrototype); | ||
RejectedPromise.prototype.inspect = function() { | ||
return toRejectedState(this.value); | ||
}; | ||
RejectedPromise.prototype._when = function(resolve, _, __, onRejected) { | ||
try { | ||
resolve(typeof onRejected === 'function' ? onRejected(this.value) : this); | ||
} catch(e) { | ||
resolve(new RejectedPromise(e)); | ||
} | ||
}; | ||
/** | ||
* Create a progress promise with the supplied update. | ||
* @private | ||
* @param {*} value progress update value | ||
* @return {Promise} progress promise | ||
*/ | ||
function ProgressingPromise(value) { | ||
this.value = value; | ||
} | ||
ProgressingPromise.prototype = makePromisePrototype(promisePrototype); | ||
ProgressingPromise.prototype._when = function(_, notify, f, r, u) { | ||
try { | ||
notify(typeof u === 'function' ? u(this.value) : this.value); | ||
} catch(e) { | ||
notify(e); | ||
} | ||
}; | ||
/** | ||
* Update a PromiseStatus monitor object with the outcome | ||
* of the supplied value promise. | ||
* @param {Promise} value | ||
* @param {PromiseStatus} status | ||
*/ | ||
function updateStatus(value, status) { | ||
value.then(statusFulfilled, statusRejected); | ||
function statusFulfilled() { status.fulfilled(); } | ||
function statusRejected(r) { status.rejected(r); } | ||
} | ||
/** | ||
* Determines if x is promise-like, i.e. a thenable object | ||
@@ -527,133 +162,31 @@ * NOTE: Will return true for *any thenable object*, and isn't truly | ||
/** | ||
* Initiates a competitive race, returning a promise that will resolve when | ||
* howMany of the supplied promisesOrValues have resolved, or will reject when | ||
* it becomes impossible for howMany to resolve, for example, when | ||
* (promisesOrValues.length - howMany) + 1 input promises reject. | ||
* | ||
* @param {Array} promisesOrValues array of anything, may contain a mix | ||
* of promises and values | ||
* @param howMany {number} number of promisesOrValues to resolve | ||
* @param {function?} [onFulfilled] DEPRECATED, use returnedPromise.then() | ||
* @param {function?} [onRejected] DEPRECATED, use returnedPromise.then() | ||
* @param {function?} [onProgress] DEPRECATED, use returnedPromise.then() | ||
* @returns {Promise} promise that will resolve to an array of howMany values that | ||
* resolved first, or will reject with an array of | ||
* (promisesOrValues.length - howMany) + 1 rejection reasons. | ||
*/ | ||
function some(promisesOrValues, howMany, onFulfilled, onRejected, onProgress) { | ||
return when(promisesOrValues, function(promisesOrValues) { | ||
return promise(resolveSome).then(onFulfilled, onRejected, onProgress); | ||
function resolveSome(resolve, reject, notify) { | ||
var toResolve, toReject, values, reasons, fulfillOne, rejectOne, len, i; | ||
len = promisesOrValues.length >>> 0; | ||
toResolve = Math.max(0, Math.min(howMany, len)); | ||
values = []; | ||
toReject = (len - toResolve) + 1; | ||
reasons = []; | ||
// No items in the input, resolve immediately | ||
if (!toResolve) { | ||
resolve(values); | ||
} else { | ||
rejectOne = function(reason) { | ||
reasons.push(reason); | ||
if(!--toReject) { | ||
fulfillOne = rejectOne = identity; | ||
reject(reasons); | ||
} | ||
}; | ||
fulfillOne = function(val) { | ||
// This orders the values based on promise resolution order | ||
values.push(val); | ||
if (!--toResolve) { | ||
fulfillOne = rejectOne = identity; | ||
resolve(values); | ||
} | ||
}; | ||
for(i = 0; i < len; ++i) { | ||
if(i in promisesOrValues) { | ||
when(promisesOrValues[i], fulfiller, rejecter, notify); | ||
} | ||
} | ||
} | ||
function rejecter(reason) { | ||
rejectOne(reason); | ||
} | ||
function fulfiller(val) { | ||
fulfillOne(val); | ||
} | ||
} | ||
}); | ||
} | ||
/** | ||
* Initiates a competitive race, returning a promise that will resolve when | ||
* any one of the supplied promisesOrValues has resolved or will reject when | ||
* *all* promisesOrValues have rejected. | ||
* | ||
* @param {Array|Promise} promisesOrValues array of anything, may contain a mix | ||
* of {@link Promise}s and values | ||
* @param {function?} [onFulfilled] DEPRECATED, use returnedPromise.then() | ||
* @param {function?} [onRejected] DEPRECATED, use returnedPromise.then() | ||
* @param {function?} [onProgress] DEPRECATED, use returnedPromise.then() | ||
* @returns {Promise} promise that will resolve to the value that resolved first, or | ||
* will reject with an array of all rejected inputs. | ||
*/ | ||
function any(promisesOrValues, onFulfilled, onRejected, onProgress) { | ||
function unwrapSingleResult(val) { | ||
return onFulfilled ? onFulfilled(val[0]) : val[0]; | ||
} | ||
return some(promisesOrValues, 1, unwrapSingleResult, onRejected, onProgress); | ||
} | ||
/** | ||
* Return a promise that will resolve only once all the supplied promisesOrValues | ||
* Return a promise that will resolve only once all the supplied arguments | ||
* have resolved. The resolution value of the returned promise will be an array | ||
* containing the resolution values of each of the promisesOrValues. | ||
* @memberOf when | ||
* | ||
* @param {Array|Promise} promisesOrValues array of anything, may contain a mix | ||
* of {@link Promise}s and values | ||
* @param {function?} [onFulfilled] DEPRECATED, use returnedPromise.then() | ||
* @param {function?} [onRejected] DEPRECATED, use returnedPromise.then() | ||
* @param {function?} [onProgress] DEPRECATED, use returnedPromise.then() | ||
* containing the resolution values of each of the arguments. | ||
* @param {...*} arguments may be a mix of promises and values | ||
* @returns {Promise} | ||
*/ | ||
function all(promisesOrValues, onFulfilled, onRejected, onProgress) { | ||
return _map(promisesOrValues, identity).then(onFulfilled, onRejected, onProgress); | ||
function join(/* ...promises */) { | ||
return Promise.all(arguments); | ||
} | ||
/** | ||
* Joins multiple promises into a single returned promise. | ||
* @return {Promise} a promise that will fulfill when *all* the input promises | ||
* have fulfilled, or will reject when *any one* of the input promises rejects. | ||
* Return a promise that will fulfill once all input promises have | ||
* fulfilled, or reject when any one input promise rejects. | ||
* @param {array|Promise} promises array (or promise for an array) of promises | ||
* @returns {Promise} | ||
*/ | ||
function join(/* ...promises */) { | ||
return _map(arguments, identity); | ||
function all(promises) { | ||
return when(promises, Promise.all); | ||
} | ||
/** | ||
* Settles all input promises such that they are guaranteed not to | ||
* be pending once the returned promise fulfills. The returned promise | ||
* will always fulfill, except in the case where `array` is a promise | ||
* that rejects. | ||
* @param {Array|Promise} array or promise for array of promises to settle | ||
* @returns {Promise} promise that always fulfills with an array of | ||
* outcome snapshots for each input promise. | ||
* Return a promise that will always fulfill with an array containing | ||
* the outcome states of all input promises. The returned promise | ||
* will only reject if `promises` itself is a rejected promise. | ||
* @param {array|Promise} promises array (or promise for an array) of promises | ||
* @returns {Promise} | ||
*/ | ||
function settle(array) { | ||
return _map(array, toFulfilledState, toRejectedState); | ||
function settle(promises) { | ||
return when(promises, Promise.settle); | ||
} | ||
@@ -664,3 +197,3 @@ | ||
* but input array may contain promises or values. | ||
* @param {Array|Promise} array array of anything, may contain promises and values | ||
* @param {Array|Promise} promises array of anything, may contain promises and values | ||
* @param {function} mapFunc map function which may return a promise or value | ||
@@ -670,51 +203,5 @@ * @returns {Promise} promise that will fulfill with an array of mapped values | ||
*/ | ||
function map(array, mapFunc) { | ||
return _map(array, mapFunc); | ||
} | ||
/** | ||
* Internal map that allows a fallback to handle rejections | ||
* @param {Array|Promise} array array of anything, may contain promises and values | ||
* @param {function} mapFunc map function which may return a promise or value | ||
* @param {function?} fallback function to handle rejected promises | ||
* @returns {Promise} promise that will fulfill with an array of mapped values | ||
* or reject if any input promise rejects. | ||
*/ | ||
function _map(array, mapFunc, fallback) { | ||
return when(array, function(array) { | ||
return new Promise(resolveMap); | ||
function resolveMap(resolve, reject, notify) { | ||
var results, len, toResolve, i; | ||
// Since we know the resulting length, we can preallocate the results | ||
// array to avoid array expansions. | ||
toResolve = len = array.length >>> 0; | ||
results = []; | ||
if(!toResolve) { | ||
resolve(results); | ||
return; | ||
} | ||
// Since mapFunc may be async, get all invocations of it into flight | ||
for(i = 0; i < len; i++) { | ||
if(i in array) { | ||
resolveOne(array[i], i); | ||
} else { | ||
--toResolve; | ||
} | ||
} | ||
function resolveOne(item, i) { | ||
when(item, mapFunc, fallback).then(function(mapped) { | ||
results[i] = mapped; | ||
if(!--toResolve) { | ||
resolve(results); | ||
} | ||
}, reject, notify); | ||
} | ||
} | ||
function map(promises, mapFunc) { | ||
return when(promises, function(promises) { | ||
return Promise.map(promises, mapFunc); | ||
}); | ||
@@ -729,215 +216,38 @@ } | ||
* | ||
* @param {Array|Promise} promise array or promise for an array of anything, | ||
* @param {Array|Promise} promises array or promise for an array of anything, | ||
* may contain a mix of promises and values. | ||
* @param {function} reduceFunc reduce function reduce(currentValue, nextValue, index, total), | ||
* where total is the total number of items being reduced, and will be the same | ||
* in each call to reduceFunc. | ||
* @param {function} f reduce function reduce(currentValue, nextValue, index) | ||
* @returns {Promise} that will resolve to the final reduced value | ||
*/ | ||
function reduce(promise, reduceFunc /*, initialValue */) { | ||
var args = fcall(slice, arguments, 1); | ||
return when(promise, function(array) { | ||
var total; | ||
total = array.length; | ||
// Wrap the supplied reduceFunc with one that handles promises and then | ||
// delegates to the supplied. | ||
args[0] = function (current, val, i) { | ||
return when(current, function (c) { | ||
return when(val, function (value) { | ||
return reduceFunc(c, value, i, total); | ||
}); | ||
}); | ||
}; | ||
return reduceArray.apply(array, args); | ||
function reduce(promises, f /*, initialValue */) { | ||
/*jshint unused:false*/ | ||
var args = slice.call(arguments, 1); | ||
return when(promises, function(array) { | ||
args.unshift(array); | ||
return Promise.reduce.apply(Promise, args); | ||
}); | ||
} | ||
// Snapshot states | ||
/** | ||
* Creates a fulfilled state snapshot | ||
* @private | ||
* @param {*} x any value | ||
* @returns {{state:'fulfilled',value:*}} | ||
* 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} f reduce function reduce(currentValue, nextValue, index) | ||
* @returns {Promise} that will resolve to the final reduced value | ||
*/ | ||
function toFulfilledState(x) { | ||
return { state: 'fulfilled', value: x }; | ||
function reduceRight(promises, f /*, initialValue */) { | ||
/*jshint unused:false*/ | ||
var args = slice.call(arguments, 1); | ||
return when(promises, function(array) { | ||
args.unshift(array); | ||
return Promise.reduceRight.apply(Promise, args); | ||
}); | ||
} | ||
/** | ||
* Creates a rejected state snapshot | ||
* @private | ||
* @param {*} x any reason | ||
* @returns {{state:'rejected',reason:*}} | ||
*/ | ||
function toRejectedState(x) { | ||
return { state: 'rejected', reason: x }; | ||
} | ||
/** | ||
* Creates a pending state snapshot | ||
* @private | ||
* @returns {{state:'pending'}} | ||
*/ | ||
function toPendingState() { | ||
return { state: 'pending' }; | ||
} | ||
// | ||
// Internals, utilities, etc. | ||
// | ||
var promisePrototype, makePromisePrototype, reduceArray, slice, fcall, nextTick, handlerQueue, | ||
funcProto, call, arrayProto, monitorApi, | ||
capturedSetTimeout, cjsRequire, MutationObs, undef; | ||
cjsRequire = require; | ||
// | ||
// Shared handler queue processing | ||
// | ||
// Credit to Twisol (https://github.com/Twisol) for suggesting | ||
// this type of extensible queue + trampoline approach for | ||
// next-tick conflation. | ||
handlerQueue = []; | ||
/** | ||
* Enqueue a task. If the queue is not currently scheduled to be | ||
* drained, schedule it. | ||
* @param {function} task | ||
*/ | ||
function enqueue(task) { | ||
if(handlerQueue.push(task) === 1) { | ||
nextTick(drainQueue); | ||
} | ||
} | ||
/** | ||
* Drain the handler queue entirely, being careful to allow the | ||
* queue to be extended while it is being processed, and to continue | ||
* processing until it is truly empty. | ||
*/ | ||
function drainQueue() { | ||
runHandlers(handlerQueue); | ||
handlerQueue = []; | ||
} | ||
// Allow attaching the monitor to when() if env has no console | ||
monitorApi = typeof console !== 'undefined' ? console : when; | ||
// Sniff "best" async scheduling option | ||
// Prefer process.nextTick or MutationObserver, then check for | ||
// vertx and finally fall back to setTimeout | ||
/*global process,document,setTimeout,MutationObserver,WebKitMutationObserver*/ | ||
if (typeof process === 'object' && process.nextTick) { | ||
nextTick = process.nextTick; | ||
} else if(MutationObs = | ||
(typeof MutationObserver === 'function' && MutationObserver) || | ||
(typeof WebKitMutationObserver === 'function' && WebKitMutationObserver)) { | ||
nextTick = (function(document, MutationObserver, drainQueue) { | ||
var el = document.createElement('div'); | ||
new MutationObserver(drainQueue).observe(el, { attributes: true }); | ||
return function() { | ||
el.setAttribute('x', 'x'); | ||
}; | ||
}(document, MutationObs, drainQueue)); | ||
} else { | ||
try { | ||
// vert.x 1.x || 2.x | ||
nextTick = cjsRequire('vertx').runOnLoop || cjsRequire('vertx').runOnContext; | ||
} catch(ignore) { | ||
// capture setTimeout to avoid being caught by fake timers | ||
// used in time based tests | ||
capturedSetTimeout = setTimeout; | ||
nextTick = function(t) { capturedSetTimeout(t, 0); }; | ||
} | ||
} | ||
// | ||
// Capture/polyfill function and array utils | ||
// | ||
// Safe function calls | ||
funcProto = Function.prototype; | ||
call = funcProto.call; | ||
fcall = funcProto.bind | ||
? call.bind(call) | ||
: function(f, context) { | ||
return f.apply(context, slice.call(arguments, 2)); | ||
}; | ||
// Safe array ops | ||
arrayProto = []; | ||
slice = arrayProto.slice; | ||
// ES5 reduce implementation if native not available | ||
// See: http://es5.github.com/#x15.4.4.21 as there are many | ||
// specifics and edge cases. ES5 dictates that reduce.length === 1 | ||
// This implementation deviates from ES5 spec in the following ways: | ||
// 1. It does not check if reduceFunc is a Callable | ||
reduceArray = arrayProto.reduce || | ||
function(reduceFunc /*, initialValue */) { | ||
/*jshint maxcomplexity: 7*/ | ||
var arr, args, reduced, len, i; | ||
i = 0; | ||
arr = Object(this); | ||
len = arr.length >>> 0; | ||
args = arguments; | ||
// If no initialValue, use first item of array (we know length !== 0 here) | ||
// and adjust i to start at second item | ||
if(args.length <= 1) { | ||
// Skip to the first real element in the array | ||
for(;;) { | ||
if(i in arr) { | ||
reduced = arr[i++]; | ||
break; | ||
} | ||
// If we reached the end of the array without finding any real | ||
// elements, it's a TypeError | ||
if(++i >= len) { | ||
throw new TypeError(); | ||
} | ||
} | ||
} else { | ||
// If initialValue provided, use it | ||
reduced = args[1]; | ||
} | ||
// Do the actual reduce | ||
for(;i < len; ++i) { | ||
if(i in arr) { | ||
reduced = reduceFunc(reduced, arr[i], i, arr); | ||
} | ||
} | ||
return reduced; | ||
}; | ||
function identity(x) { | ||
return x; | ||
} | ||
function crash(fatalError) { | ||
if(typeof monitorApi.reportUnhandled === 'function') { | ||
monitorApi.reportUnhandled(); | ||
} else { | ||
enqueue(function() { | ||
throw fatalError; | ||
}); | ||
} | ||
throw fatalError; | ||
} | ||
return when; | ||
}); | ||
})(typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); }); |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
146255
46
3587
106
7
1