Comparing version 1.8.1 to 2.0.0
10
apply.js
@@ -61,11 +61,7 @@ /** @license MIT License (c) copyright B Cavalier & J Hann */ | ||
}); | ||
})(typeof define == 'function' | ||
? define | ||
: function (factory) { typeof module != 'undefined' | ||
? (module.exports = factory()) | ||
: (this.when_apply = factory()); | ||
} | ||
// Boilerplate for AMD, Node, and browser global | ||
})( | ||
typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); } | ||
// Boilerplate for AMD and Node | ||
); | ||
356
callbacks.js
@@ -10,12 +10,18 @@ /** @license MIT License (c) copyright 2013 original author or authors */ | ||
* @author Renato Zannon <renato.riccieri@gmail.com> | ||
* @contributor Brian Cavalier | ||
*/ | ||
(function(define) { | ||
define(['./when'], function(when) { | ||
var slice = [].slice; | ||
define(function(require) { | ||
var when, slice; | ||
when = require('./when'); | ||
slice = [].slice; | ||
return { | ||
apply: apply, | ||
call: call, | ||
bind: bind, | ||
apply: apply, | ||
call: call, | ||
lift: lift, | ||
bind: lift, // DEPRECATED alias for lift | ||
promisify: promisify | ||
@@ -25,32 +31,31 @@ }; | ||
/** | ||
* 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 | ||
*/ | ||
* 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) { | ||
@@ -72,22 +77,21 @@ return when.all(extraAsyncArgs || []).then(function(args) { | ||
/** | ||
* 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 | ||
*/ | ||
* 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...*/) { | ||
@@ -99,35 +103,35 @@ var extraAsyncArgs = 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 `bind` 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.bind(traditionalAjax); | ||
* promiseAjax("GET", "/movies.json").then(console.log, console.error); | ||
* | ||
* var promiseAjaxGet = callbacks.bind(traditionalAjax, "GET"); | ||
* promiseAjaxGet("/movies.json").then(console.log, console.error); | ||
* | ||
* @param {Function} asyncFunction traditional function to be decorated | ||
* @param {...*} [args] arguments to be prepended for the new function | ||
* @returns {Function} a promise-returning function | ||
*/ | ||
function bind(asyncFunction/*, args...*/) { | ||
* 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 `bind` 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.bind(traditionalAjax); | ||
* promiseAjax("GET", "/movies.json").then(console.log, console.error); | ||
* | ||
* var promiseAjaxGet = callbacks.bind(traditionalAjax, "GET"); | ||
* promiseAjaxGet("/movies.json").then(console.log, console.error); | ||
* | ||
* @param {Function} asyncFunction traditional function to be decorated | ||
* @param {...*} [args] arguments to be prepended for the new function | ||
* @returns {Function} a promise-returning function | ||
*/ | ||
function lift(asyncFunction/*, args...*/) { | ||
var leadingArgs = slice.call(arguments, 1); | ||
@@ -142,104 +146,94 @@ | ||
/** | ||
* `promisify` is a version of `bind` 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); | ||
* | ||
*/ | ||
* `promisify` is a version of `bind` 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 | ||
*/ | ||
function promisify(asyncFunction, positions) { | ||
return function() { | ||
var finalArgs = fillableArray(); | ||
var deferred = when.defer(); | ||
return when.all(arguments).then(function(args) { | ||
if('callback' in positions) { | ||
finalArgs.add(positions.callback, alwaysUnary(deferred.resolve)); | ||
} | ||
var deferred, callbackPos, errbackPos; | ||
if('errback' in positions) { | ||
finalArgs.add(positions.errback, alwaysUnary(deferred.reject)); | ||
} | ||
if('callback' in positions) { | ||
callbackPos = normalizePosition(args, positions.callback); | ||
} | ||
return when.all(arguments).then(function(args) { | ||
finalArgs.fillHolesWith(args); | ||
asyncFunction.apply(null, finalArgs.toArray()); | ||
if('errback' in positions) { | ||
errbackPos = normalizePosition(args, positions.errback); | ||
} | ||
return deferred.promise; | ||
}); | ||
}; | ||
} | ||
deferred = when.defer(); | ||
function fillableArray() { | ||
var beginningArgs = [], endArgs = []; | ||
return { | ||
add: function(index, value) { | ||
if(index >= 0) { | ||
beginningArgs[index] = value; | ||
if(errbackPos < callbackPos) { | ||
insertCallback(args, errbackPos, deferred.reject); | ||
insertCallback(args, callbackPos, deferred.resolve); | ||
} else { | ||
// Since we can't know how many arguments at the end there'll be | ||
// (there might be -1, -2, -3...), we fill the array containing them | ||
// in reverse order: from the element that will be the last argument | ||
// (-1), following to the penultimate (-2) etc. | ||
var offsetFromEnd = Math.abs(index) - 1; | ||
endArgs[offsetFromEnd] = value; | ||
insertCallback(args, callbackPos, deferred.resolve); | ||
insertCallback(args, errbackPos, deferred.reject); | ||
} | ||
}, | ||
fillHolesWith: function(arrayLike) { | ||
var i, j; | ||
asyncFunction.apply(null, args); | ||
for(i = 0, j = 0; i < arrayLike.length; i++, j++) { | ||
while(j in beginningArgs) { j++; } | ||
beginningArgs[j] = arrayLike[i]; | ||
} | ||
}, | ||
return deferred.promise; | ||
}); | ||
}; | ||
} | ||
toArray: function() { | ||
var result = slice.call(beginningArgs, 0); | ||
function normalizePosition(args, pos) { | ||
return pos < 0 ? (args.length + pos + 2) : pos; | ||
} | ||
// Now, the 'endArgs' array is supposedly finished, and we can traverse | ||
// it to get the elements that should be appended to the array. Since | ||
// the elements are in reversed order, we traverse it from back to | ||
// front. | ||
for(var i = endArgs.length - 1; i >= 0; i--) { | ||
result.push(endArgs[i]); | ||
} | ||
function insertCallback(args, pos, callback) { | ||
if(pos != null) { | ||
callback = alwaysUnary(callback); | ||
if(pos < 0) { | ||
pos = args.length + pos + 2; | ||
} | ||
args.splice(pos, 0, callback); | ||
} | ||
return result; | ||
} | ||
}; | ||
} | ||
@@ -257,9 +251,5 @@ | ||
}); | ||
})(typeof define == 'function' | ||
? define | ||
: function (deps, factory) { typeof module != 'undefined' | ||
? (module.exports = factory(require('./when'))) | ||
: (this.when_callback = factory(this.when)); | ||
} | ||
// Boilerplate for AMD, Node, and browser global | ||
})( | ||
typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); } | ||
// Boilerplate for AMD and Node | ||
); |
@@ -19,4 +19,6 @@ /** @license MIT License (c) copyright B Cavalier & J Hann */ | ||
(function(define) { | ||
define(['./when'], function(when) { | ||
define(function(require) { | ||
var when = require('./when'); | ||
/** | ||
@@ -26,6 +28,7 @@ * Makes deferred cancelable, adding a cancel() method. | ||
* @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() | ||
* @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() | ||
* | ||
@@ -41,3 +44,3 @@ * @returns deferred, with an added cancel() method. | ||
deferred.cancel = function() { | ||
return delegate.reject(canceler(deferred)); | ||
return deferred.reject(canceler(deferred)); | ||
}; | ||
@@ -61,11 +64,7 @@ | ||
}); | ||
})(typeof define == 'function' | ||
? define | ||
: function (deps, factory) { typeof module != 'undefined' | ||
? (module.exports = factory(require('./when'))) | ||
: (this.when_cancelable = factory(this.when)); | ||
} | ||
// Boilerplate for AMD, Node, and browser global | ||
})( | ||
typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); } | ||
// Boilerplate for AMD and Node | ||
); | ||
@@ -0,1 +1,11 @@ | ||
### 2.0.0 | ||
* Fully asynchronous resolutions. | ||
* [Promises/A+](http://promises-aplus.github.com/promises-spec) compliance. | ||
* New [`when/keys`](docs/api.md#object-keys) module with `all()` and `map()` for object keys/values. | ||
* New [`promise.ensure`](docs/api.md#ensure) as a better, and safer, replacement for `promise.always`. [See discussion](https://github.com/cujojs/when/issues/103) as to why `promise.always` is mistake-prone. | ||
* **DEPRECATED:** `promise.always` | ||
* `lift()` is now the preferred name for what was `bind()` in [when/function](docs/api.md#synchronous-functions), [when/node/function](docs/api.md#node-style-asynchronous-functions), and [when/callbacks](docs/api.md#asynchronous-functions). | ||
* **DEPRECATED:** `bind()` in `when/function`, `when/node/function`, and `when/callbacks`. Use `lift()` instead. | ||
### 1.8.1 | ||
@@ -2,0 +12,0 @@ |
50
debug.js
@@ -37,6 +37,7 @@ /** @license MIT License (c) copyright B Cavalier & J Hann */ | ||
(function(define) { | ||
define(['./when'], function(when) { | ||
define(function(require) { | ||
var promiseId, pending, exceptionsToRethrow, own, warn, undef; | ||
var when, promiseId, pending, exceptionsToRethrow, own, warn, undef; | ||
when = require('./when'); | ||
promiseId = 0; | ||
@@ -140,3 +141,3 @@ pending = {}; | ||
function deferDebug(/* id */) { | ||
var d, status, value, origResolve, origReject, origNotify, origThen, id; | ||
var d, err, status, value, origResolve, origReject, origNotify, origThen, origAlways, id; | ||
@@ -146,2 +147,16 @@ // Delegate to create a Deferred; | ||
// TODO: Remove in >= 2.1 | ||
// Add a noisy, failing then() to deferred to help people track | ||
// down leftover deferred.then() calls in 2.0 | ||
try { | ||
throw new Error('deferred.then was removed, use deferred.promise.then'); | ||
} catch (e) { | ||
err = e; | ||
} | ||
d.then = function deferredThenIsDeprecated() { | ||
throwUncatchable(err); | ||
}; | ||
// End Remove 2.1 | ||
status = 'pending'; | ||
@@ -164,2 +179,5 @@ value = pending; | ||
origAlways = d.promise.always; | ||
d.promise.always = deprecated('promise.always', 'promise.ensure', origAlways, d.promise); | ||
d.resolver = beget(d.resolver); | ||
@@ -171,8 +189,3 @@ d.resolver.toString = function() { | ||
origNotify = d.resolver.notify; | ||
d.notify = d.resolver.notify = promiseNotify; | ||
// deferred.progress and deferred.resolver.progress are DEPRECATED. | ||
d.progress = deprecated('deferred.progress', 'deferred.notify', promiseNotify, d); | ||
d.resolver.progress = deprecated('deferred.resolver.progress', 'deferred.resolver.notify', promiseNotify, d.resolver); | ||
function promiseNotify(update) { | ||
d.notify = d.resolver.notify = function(update) { | ||
// Notify global debug handler, if set | ||
@@ -182,3 +195,3 @@ callGlobalHandler('progress', d, update); | ||
return origNotify(update); | ||
} | ||
}; | ||
@@ -213,4 +226,2 @@ origResolve = d.resolver.resolve; | ||
d.then = deprecated('deferred.then', 'deferred.promise.then', d.promise.then, d); | ||
// Add an id to all directly created promises. It'd be great | ||
@@ -225,6 +236,2 @@ // to find a way to propagate this id to promise created by .then() | ||
whenDebug.isPromise = when.isPromise; | ||
whenDebug.chain = deprecated( | ||
'when.chain(p, resolver)', | ||
'resolver.resolve(p) or resolver.resolve(p.yield(optionalValue))', | ||
when.chain, when); | ||
@@ -328,2 +335,3 @@ // For each method we haven't already replaced, replace it with | ||
// Commented out until we need it, to appease JSHint | ||
function deprecated(name, preferred, f, context) { | ||
@@ -362,9 +370,5 @@ return function() { | ||
}); | ||
})(typeof define == 'function' | ||
? define | ||
: function (deps, factory) { typeof exports != 'undefined' | ||
? (module.exports = factory(require('./when'))) | ||
: (this.when = factory(this.when)); | ||
} | ||
// Boilerplate for AMD, Node, and browser global | ||
})( | ||
typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); } | ||
// Boilerplate for AMD and Node | ||
); |
28
delay.js
@@ -14,6 +14,8 @@ /** @license MIT License (c) copyright B Cavalier & J Hann */ | ||
(function(define) { | ||
define(['./when'], function(when) { | ||
define(function(require) { | ||
var undef; | ||
var when, undef; | ||
when = require('./when'); | ||
/** | ||
@@ -45,5 +47,11 @@ * Creates a new promise that will resolve after a msec delay. If promise | ||
setTimeout(function() { | ||
deferred.resolve(promise); | ||
}, msec); | ||
when(promise, | ||
function(val) { | ||
setTimeout(function() { | ||
deferred.resolve(val); | ||
}, msec); | ||
}, | ||
deferred.reject, | ||
deferred.notify | ||
); | ||
@@ -54,11 +62,7 @@ return deferred.promise; | ||
}); | ||
})(typeof define == 'function' | ||
? define | ||
: function (deps, factory) { typeof module != 'undefined' | ||
? (module.exports = factory(require('./when'))) | ||
: (this.when_delay = factory(this.when)); | ||
} | ||
// Boilerplate for AMD, Node, and browser global | ||
})( | ||
typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); } | ||
// Boilerplate for AMD and Node | ||
); | ||
296
function.js
@@ -1,2 +0,2 @@ | ||
/** @license MIT License (c) copyright B Cavalier & J Hann */ | ||
/** @license MIT License (c) copyright 2013 original author or authors */ | ||
@@ -6,3 +6,3 @@ /** | ||
* | ||
* Collection of helper functions for wraping and executing 'traditional' | ||
* Collection of helper functions for wrapping and executing 'traditional' | ||
* synchronous functions in a promise interface. | ||
@@ -15,7 +15,8 @@ * | ||
(function(define) { | ||
define(['./when'], function(when) { | ||
define(function(require) { | ||
var slice; | ||
var when, slice; | ||
slice = Array.prototype.slice; | ||
when = require('./when'); | ||
slice = [].slice; | ||
@@ -25,3 +26,4 @@ return { | ||
call: call, | ||
bind: bind, | ||
lift: lift, | ||
bind: lift, // DEPRECATED alias for lift | ||
compose: compose | ||
@@ -31,26 +33,25 @@ }; | ||
/** | ||
* 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. | ||
* | ||
* @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 {Array} [args] array of arguments to func | ||
* @returns {Promise} promise for the return value of func | ||
*/ | ||
* 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. | ||
* | ||
* @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 {Array} [args] array of arguments to func | ||
* @returns {Promise} promise for the return value of func | ||
*/ | ||
function apply(func, promisedArgs) { | ||
@@ -63,27 +64,26 @@ return when.all(promisedArgs || [], function(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 | ||
*/ | ||
* 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... */) { | ||
@@ -94,43 +94,42 @@ return apply(func, slice.call(arguments, 1)); | ||
/** | ||
* 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. | ||
* | ||
* @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 bound = fn.bind(mayThrowError); | ||
* | ||
* // Logs "I don't like odd numbers" | ||
* bound(1).then(console.log, console.error); | ||
* | ||
* // Logs '6' | ||
* bound(6).then(console.log, console.error); | ||
* | ||
* @example | ||
* function sumTwoNumbers(x, y) { | ||
* return x + y; | ||
* } | ||
* | ||
* var sumWithFive = fn.bind(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 | ||
*/ | ||
function bind(func /*, 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. | ||
* | ||
* @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 | ||
*/ | ||
function lift(func /*, args... */) { | ||
var args = slice.call(arguments, 1); | ||
@@ -143,50 +142,49 @@ return function() { | ||
/** | ||
* 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'. | ||
* | ||
* @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 | ||
* @param {...Function} [funcs] functions that will be composed, in order | ||
* @returns {Function} a promise-returning composition of the functions | ||
*/ | ||
* 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'. | ||
* | ||
* @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 | ||
* @param {...Function} [funcs] functions that will be composed, in order | ||
* @returns {Function} a promise-returning composition of the functions | ||
*/ | ||
function compose(f /*, funcs... */) { | ||
@@ -206,11 +204,7 @@ var funcs = slice.call(arguments, 1); | ||
})(typeof define == 'function' | ||
? define | ||
: function (deps, factory) { typeof exports != 'undefined' | ||
? (module.exports = factory(require('./when'))) | ||
: (this.when_function = factory(this.when)); | ||
} | ||
// Boilerplate for AMD, Node, and browser global | ||
})( | ||
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 B Cavalier & J Hann */ | ||
/** @license MIT License (c) copyright 2013 original author or authors */ | ||
@@ -14,7 +14,8 @@ /** | ||
(function(define) { | ||
define(['../when'], function(when) { | ||
define(function(require) { | ||
var slice; | ||
var when, slice; | ||
slice = Array.prototype.slice; | ||
when = require('../when'); | ||
slice = [].slice; | ||
@@ -24,3 +25,4 @@ return { | ||
call: call, | ||
bind: bind, | ||
lift: lift, | ||
bind: lift, // DEPRECATED alias for lift | ||
createCallback: createCallback | ||
@@ -30,32 +32,31 @@ }; | ||
/** | ||
* 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 | ||
* | ||
*/ | ||
* 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) { | ||
@@ -73,26 +74,26 @@ return when.all(args || []).then(function(resolvedArgs) { | ||
/** | ||
* 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 | ||
*/ | ||
* 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... */) { | ||
@@ -103,32 +104,32 @@ return apply(func, 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.bind(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 bind(func /*, args... */) { | ||
* 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.bind(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); | ||
@@ -164,3 +165,3 @@ return function() { | ||
* @returns {Function} a node-style callback function | ||
**/ | ||
*/ | ||
function createCallback(resolver) { | ||
@@ -179,9 +180,5 @@ return function(err, value) { | ||
})(typeof define == 'function' | ||
? define | ||
: function (deps, factory) { typeof exports != 'undefined' | ||
? (module.exports = factory(require('../when'))) | ||
: (this.when_node_function = factory(this.when)); | ||
} | ||
// Boilerplate for AMD, Node, and browser global | ||
})( | ||
typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); } | ||
// Boilerplate for AMD and Node | ||
); | ||
@@ -188,0 +185,0 @@ |
{ | ||
"name": "when", | ||
"version": "1.8.1", | ||
"version": "2.0.0", | ||
"description": "A lightweight Promise and when() implementation, plus other async goodies.", | ||
@@ -30,5 +30,5 @@ "keywords": ["promise", "promises", "deferred", "deferreds", "when", "async", "asynchronous", "cujo"], | ||
"devDependencies": { | ||
"buster": "~0.6", | ||
"jshint": "~1.0", | ||
"promise-tests": "*" | ||
"curl": "https://github.com/cujojs/curl/tarball/0.7.3", | ||
"test-support": "~0.1", | ||
"promises-aplus-tests": "~1" | ||
}, | ||
@@ -40,7 +40,6 @@ "main": "when", | ||
"scripts": { | ||
"test": "jshint *.js && buster test -e node && promise-tests promises-a test/when-adapter.js", | ||
"test-all": "jshint *.js && buster test -e node && promise-tests all test/when-adapter.js", | ||
"start": "buster server", | ||
"test-browser": "jshint *.js && buster test -e browser" | ||
"test": "jshint . && buster test -e node && promises-aplus-tests test/when-adapter.js", | ||
"ci": "npm test && sauceme", | ||
"start": "buster static -e browser" | ||
} | ||
} |
@@ -13,4 +13,8 @@ /** @license MIT License (c) copyright B Cavalier & J Hann */ | ||
(function(define) { | ||
define(['./when'], function(when) { | ||
define(function(require) { | ||
var when; | ||
when = require('./when'); | ||
/** | ||
@@ -32,11 +36,7 @@ * Run array of tasks in parallel | ||
}); | ||
})(typeof define == 'function' && define.amd | ||
? define | ||
: function (deps, factory) { typeof exports == 'object' | ||
? (module.exports = factory(require('./when'))) | ||
: (this.when_parallel = factory(this.when)); | ||
} | ||
// Boilerplate for AMD, Node, and browser global | ||
})( | ||
typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); } | ||
// Boilerplate for AMD and Node | ||
); | ||
@@ -14,4 +14,8 @@ /** @license MIT License (c) copyright B Cavalier & J Hann */ | ||
(function(define) { | ||
define(['./when'], function(when) { | ||
define(function(require) { | ||
var when; | ||
when = require('./when'); | ||
/** | ||
@@ -49,11 +53,7 @@ * Run array of tasks in a pipeline where the next | ||
}); | ||
})(typeof define == 'function' && define.amd | ||
? define | ||
: function (deps, factory) { typeof exports == 'object' | ||
? (module.exports = factory(require('./when'))) | ||
: (this.when_pipeline = factory(this.when)); | ||
} | ||
// Boilerplate for AMD, Node, and browser global | ||
})( | ||
typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); } | ||
// Boilerplate for AMD and Node | ||
); | ||
19
poll.js
@@ -13,6 +13,11 @@ /** @license MIT License (c) copyright 2012-2013 original author or authors */ | ||
'use strict'; | ||
define(['./when', './cancelable', './delay', './function'], function(when, cancelable, delay, fn) { | ||
define(function(require) { | ||
var undef; | ||
var when, cancelable, delay, fn, undef; | ||
when = require('./when'); | ||
cancelable = require('./cancelable'); | ||
delay = require('./delay'); | ||
fn = require('./function'); | ||
/** | ||
@@ -124,9 +129,5 @@ * Periodically execute the work function on the msec delay. The result of | ||
}); | ||
})(typeof define == 'function' && define.amd | ||
? define | ||
: function (deps, factory) { typeof exports == 'object' | ||
? (module.exports = factory(require('./when'), require('./cancelable'), require('./delay'), require('./function'))) | ||
: (this.when_poll = factory(this.when, this.when_cancelable, this.when_delay, this.when_function)); | ||
} | ||
// Boilerplate for AMD, Node, and browser global | ||
})( | ||
typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); } | ||
// Boilerplate for AMD and Node | ||
); |
@@ -1,41 +0,28 @@ | ||
# when.js [![Build Status](https://secure.travis-ci.org/cujojs/when.png)](http://travis-ci.org/cujojs/when) | ||
<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 is cujojs's lightweight [CommonJS](http://wiki.commonjs.org/wiki/Promises) [Promises/A](http://wiki.commonjs.org/wiki/Promises/A) and `when()` implementation, derived from the async core of [wire.js](https://github.com/cujojs/wire), cujojs's IOC Container. It also provides several other useful Promise-related concepts, such as joining multiple promises, mapping and reducing collections of promises, timed promises, and has a robust [unit test suite](#running-the-unit-tests). | ||
[![Build Status](https://secure.travis-ci.org/cujojs/when.png)](http://travis-ci.org/cujojs/when) | ||
It passes the [Promises/A Test Suite](https://github.com/domenic/promise-tests), is [frighteningly fast](https://github.com/cujojs/promise-perf-tests#test-results), and is **around 1.4k** when compiled with Google Closure (w/advanced optimizations) and gzipped, and has no external dependencies. | ||
# when.js | ||
# What's New? | ||
When.js is cujojs's lightweight [Promises/A+](http://promises-aplus.github.com/promises-spec) and `when()` implementation, derived from the async core of [wire.js](https://github.com/cujojs/wire), cujojs's IOC Container. It features: | ||
### 1.8.1 | ||
* A rock solid, battle-tested Promise implementation | ||
* Resolving, mapping, and reducing arrays of promises | ||
* Executing tasks in parallel and sequence | ||
* Transforming Node-style and other callback-based APIs into promise-based APIs | ||
* Last 1.x.x release before 2.0.0 barring critical fixes. | ||
* To prepare for 2.0.0, [test your code against the dev-200 branch](https://github.com/cujojs/when/tree/dev-200). It is fully API compatible, but has fully asynchronous resolutions. | ||
* Performance improvements for [when/function](docs/api.md#synchronous-functions). | ||
* [Documentation](docs/api.md) updates and fixes. Thanks, [@unscriptable](https://github.com/unscriptable)! | ||
* **DEPRECATED:** `deferred.progress` and `deferred.resolver.progress`. Use [`deferred.notify`](docs/api.md#progress-events) and [`deferred.resolver.notify`](docs/api.md#progress-events) instead. | ||
* **DEPRECATED:** [`when.chain`](docs/api.md#whenchain). Use [`resolver.resolve(promise)`](docs/api.md#resolver) or `resolver.resolve(promise.yield)` ([see `promise.yield`](docs/api.md#yield)) instead. | ||
* **DEPRECATED:** `when/timed` module. Use [`when/delay`](docs/api.md#whendelay) and [`when/timeout`](docs/api.md#whentimeout) modules instead. | ||
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), is under 1.5k when compiled with Google Closure + gzip, and has no external dependencies. | ||
### 1.8.0 | ||
# What's New? | ||
* New [when/function](docs/api.md#synchronous-functions), [when/node/function](docs/api.md#node-style-asynchronous-functions), and [when/callbacks](docs/api.md#asynchronous-functions) with functional programming goodness, and adapters for turning callback-based APIs into promise-based APIs. Kudos [@riccieri](https://github.com/riccieri)! | ||
* New [when/unfold](docs/api.md#whenunfold), and [when/unfold/list](docs/api.md#whenunfoldlist) promise-aware anamorphic unfolds that can be used to generate and/or process unbounded lists. | ||
* New [when/poll](docs/api.md#whenpoll) promise-based periodic polling and task execution. Kudos [@scothis](https://github.com/scothis)! | ||
### 2.0.0 | ||
### 1.7.1 | ||
* Fully asynchronous resolutions. | ||
* [Promises/A+](http://promises-aplus.github.com/promises-spec) compliance. | ||
* New [`when/keys`](docs/api.md#object-keys) module with `all()` and `map()` for object keys/values. | ||
* New [`promise.ensure`](docs/api.md#ensure) as a better, and safer, replacement for `promise.always`. [See discussion](https://github.com/cujojs/when/issues/103) as to why `promise.always` is mistake-prone. | ||
* **DEPRECATED:** `promise.always` | ||
* `lift()` is now the preferred name for what was `bind()` in [when/function](docs/api.md#synchronous-functions), [when/node/function](docs/api.md#node-style-asynchronous-functions), and [when/callbacks](docs/api.md#asynchronous-functions). | ||
* **DEPRECATED:** `bind()` in `when/function`, `when/node/function`, and `when/callbacks`. Use `lift()` instead. | ||
* Removed leftover internal usages of `deferred.then`. | ||
* [when/debug](https://github.com/cujojs/when/wiki/when-debug) allows configuring the set of "fatal" error types that will be rethrown to the host env. | ||
### 1.7.0 | ||
* **DEPRECATED:** `deferred.then` [is deprecated](docs/api.md#deferred) and will be removed in an upcoming release. Use `deferred.promise.then` instead. | ||
* [promise.yield](docs/api.md#yield)(promiseOrValue) convenience API for substituting a new value into a promise chain. | ||
* [promise.spread](docs/api.md#spread)(variadicFunction) convenience API for spreading an array onto a fulfill handler that accepts variadic arguments. [Mmmm, buttery](http://s.shld.net/is/image/Sears/033W048977110001_20100422100331516?hei=1600&wid=1600&op_sharpen=1&resMode=sharp&op_usm=0.9,0.5,0,0) | ||
* Doc improvements: | ||
* [when()](docs/api.md#when) and [promise.then()](docs/api.md#main-promise-api) have more info about callbacks and chaining behavior. | ||
* More info and clarifications about the roles of [Deferred](docs/api.md#deferred) and [Resolver](docs/api.md#resolver) | ||
* Several minor clarifications for various APIs | ||
* Internal improvements to assimilation and interoperability with other promise implementations. | ||
[Full Changelog](CHANGES.md) | ||
@@ -56,6 +43,8 @@ | ||
1. `git clone https://github.com/cujojs/when` or `git submodule add https://github.com/cujojs/when` | ||
1. Get it | ||
- `bower install when` or `yeoman install when`, *or* | ||
- `git clone https://github.com/cujojs/when` or `git submodule add https://github.com/cujojs/when` | ||
1. Configure your loader with a package: | ||
```javascript | ||
```js | ||
packages: [ | ||
@@ -69,8 +58,2 @@ { name: 'when', location: 'path/to/when/', main: 'when' }, | ||
### Script Tag | ||
1. `git clone https://github.com/cujojs/when` or `git submodule add https://github.com/cujojs/when` | ||
1. `<script src="path/to/when/when.js"></script>` | ||
1. `when` will be available as `window.when` | ||
### Node | ||
@@ -86,2 +69,19 @@ | ||
### Legacy environments | ||
1. `git clone https://github.com/cujojs/when` or `git submodule add https://github.com/cujojs/when` | ||
1. Add a transient `define` shim, and a `<script>` element for when.js | ||
```html | ||
<script> | ||
window.define = function(factory) { | ||
try{ delete window.define; } catch(e){ window.define = void 0; } // IE | ||
window.when = factory(); | ||
}; | ||
</script> | ||
<script src="path/to/when/when.js"></script> | ||
``` | ||
1. `when` will be available as `window.when` | ||
# Running the Unit Tests | ||
@@ -91,3 +91,3 @@ | ||
Note that when.js includes @domenic's [Promises/A Test Suite](https://github.com/domenic/promise-tests). Running unit tests in Node will run both when.js's own test suite, and the Promises/A Test Suite. | ||
Note that when.js includes the [Promises/A+ Test Suite](https://github.com/promises-aplus/promise-tests). Running unit tests in Node will run both when.js's own test suite, and the Promises/A+ Test Suite. | ||
@@ -107,4 +107,2 @@ 1. `npm install` | ||
Much of this code was inspired by @[unscriptable](https://github.com/unscriptable)'s [tiny promises](https://github.com/unscriptable/promises), the async innards of [wire.js](https://github.com/cujojs/wire), and some gists [here](https://gist.github.com/870729), [here](https://gist.github.com/892345), [here](https://gist.github.com/894356), and [here](https://gist.github.com/894360) | ||
Some of the code has been influenced by the great work in [Q](https://github.com/kriskowal/q), [Dojo's Deferred](https://github.com/dojo/dojo), and [uber.js](https://github.com/phiggins42/uber.js). | ||
Much of this code was inspired by the async innards of [wire.js](https://github.com/cujojs/wire), and has been influenced by the great work in [Q](https://github.com/kriskowal/q), [Dojo's Deferred](https://github.com/dojo/dojo), and [uber.js](https://github.com/phiggins42/uber.js). |
@@ -13,4 +13,8 @@ /** @license MIT License (c) copyright B Cavalier & J Hann */ | ||
(function(define) { | ||
define(['./when'], function(when) { | ||
define(function(require) { | ||
var when; | ||
when = require('./when'); | ||
/** | ||
@@ -35,11 +39,7 @@ * Run array of tasks in sequence with no overlap | ||
}); | ||
})(typeof define == 'function' && define.amd | ||
? define | ||
: function (deps, factory) { typeof exports == 'object' | ||
? (module.exports = factory(require('./when'))) | ||
: (this.when_sequence = factory(this.when)); | ||
} | ||
// Boilerplate for AMD, Node, and browser global | ||
})( | ||
typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); } | ||
// Boilerplate for AMD and Node | ||
); | ||
17
timed.js
@@ -14,4 +14,9 @@ /** @license MIT License (c) copyright B Cavalier & J Hann */ | ||
(function(define) { | ||
define(['./timeout', './delay'], function(timeout, delay) { | ||
define(function(require) { | ||
var timeout, delay; | ||
timeout = require('./timeout'); | ||
delay = require('./delay'); | ||
return { | ||
@@ -23,11 +28,7 @@ timeout: timeout, | ||
}); | ||
})(typeof define == 'function' | ||
? define | ||
: function (deps, factory) { typeof module != 'undefined' | ||
? (module.exports = factory.apply(this, deps.map(require))) | ||
: (this.when_timed = factory(this.when_timeout, this.when_delay)); | ||
} | ||
// Boilerplate for AMD, Node, and browser global | ||
})( | ||
typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); } | ||
// Boilerplate for AMD and Node | ||
); | ||
@@ -15,6 +15,8 @@ /** @license MIT License (c) copyright B Cavalier & J Hann */ | ||
(function(define) { | ||
define(['./when'], function(when) { | ||
define(function(require) { | ||
var undef; | ||
var when, undef; | ||
when = require('./when'); | ||
/** | ||
@@ -60,3 +62,4 @@ * Returns a new promise that will automatically reject after msec if | ||
deferred.reject(reason); | ||
} | ||
}, | ||
deferred.notify | ||
); | ||
@@ -68,11 +71,7 @@ | ||
}); | ||
})(typeof define == 'function' | ||
? define | ||
: function (deps, factory) { typeof module != 'undefined' | ||
? (module.exports = factory(require('./when'))) | ||
: (this.when_timeout = factory(this.when)); | ||
} | ||
// Boilerplate for AMD, Node, and browser global | ||
})( | ||
typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); } | ||
// Boilerplate for AMD and Node | ||
); | ||
@@ -8,4 +8,8 @@ /** @license MIT License (c) copyright B Cavalier & J Hann */ | ||
(function(define) { | ||
define(['when'], function(when) { | ||
define(function(require) { | ||
var when; | ||
when = require('./when'); | ||
/** | ||
@@ -39,10 +43,6 @@ * Anamorphic unfold/map that generates values by applying | ||
}); | ||
})(typeof define == 'function' && define.amd | ||
? define | ||
: function (deps, factory) { typeof exports == 'object' | ||
? (module.exports = factory(require('./when'))) | ||
: (this.when_unfold = factory(this.when)); | ||
} | ||
// Boilerplate for AMD, Node, and browser global | ||
})( | ||
typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); } | ||
// Boilerplate for AMD and Node | ||
); | ||
@@ -8,4 +8,9 @@ /** @license MIT License (c) copyright B Cavalier & J Hann */ | ||
(function(define) { | ||
define(['when', 'unfold'], function(when, unfold) { | ||
define(function(require) { | ||
var when, unfold; | ||
when = require('../when'); | ||
unfold = require('../unfold'); | ||
/** | ||
@@ -33,10 +38,6 @@ * Given a seed and generator, produces an Array. Effectively the | ||
}); | ||
})(typeof define == 'function' && define.amd | ||
? define | ||
: function (deps, factory) { typeof exports == 'object' | ||
? (module.exports = factory(require('../when'), require('../unfold'))) | ||
: (this.when_unfoldList = factory(this.when, this.when_unfold)); | ||
} | ||
// Boilerplate for AMD, Node, and browser global | ||
})( | ||
typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); } | ||
// Boilerplate for AMD and Node | ||
); | ||
824
when.js
@@ -12,31 +12,24 @@ /** @license MIT License (c) copyright 2011-2013 original author or authors */ | ||
* @author John Hann | ||
* | ||
* @version 1.8.1 | ||
* @version 2.0.0 | ||
*/ | ||
(function(define) { 'use strict'; | ||
define(function () { | ||
var reduceArray, slice, undef; | ||
// | ||
// Public API | ||
// | ||
when.defer = defer; // Create a deferred | ||
when.resolve = resolve; // Create a resolved promise | ||
when.reject = reject; // Create a rejected promise | ||
when.defer = defer; // Create a deferred | ||
when.resolve = resolve; // Create a resolved promise | ||
when.reject = reject; // Create a rejected promise | ||
when.join = join; // Join 2 or more promises | ||
when.join = join; // Join 2 or more promises | ||
when.all = all; // Resolve a list of promises | ||
when.map = map; // Array.map() for promises | ||
when.reduce = reduce; // Array.reduce() for promises | ||
when.all = all; // Resolve a list of promises | ||
when.map = map; // Array.map() for promises | ||
when.reduce = reduce; // Array.reduce() for promises | ||
when.any = any; // One-winner race | ||
when.some = some; // Multi-winner race | ||
when.any = any; // One-winner race | ||
when.some = some; // Multi-winner race | ||
when.chain = chain; // Make a promise trigger another resolver | ||
when.isPromise = isPromise; // Determine if a thing is a promise | ||
when.isPromise = isPromise; // Determine if a thing is a promise | ||
/** | ||
@@ -64,73 +57,2 @@ * Register an observer for a promise or immediate value. | ||
/** | ||
* Returns promiseOrValue if promiseOrValue is a {@link Promise}, a new Promise if | ||
* promiseOrValue is a foreign promise, or a new, already-fulfilled {@link Promise} | ||
* whose value is promiseOrValue if promiseOrValue is an immediate value. | ||
* | ||
* @param {*} promiseOrValue | ||
* @returns {Promise} Guaranteed to return a trusted Promise. If promiseOrValue | ||
* is trusted, returns promiseOrValue, otherwise, returns a new, already-resolved | ||
* when.js promise whose resolution value is: | ||
* * the resolution value of promiseOrValue if it's a foreign promise, or | ||
* * promiseOrValue if it's a value | ||
*/ | ||
function resolve(promiseOrValue) { | ||
var promise; | ||
if(promiseOrValue instanceof Promise) { | ||
// It's a when.js promise, so we trust it | ||
promise = promiseOrValue; | ||
} else if(isPromise(promiseOrValue)) { | ||
// Assimilate foreign promises | ||
promise = assimilate(promiseOrValue); | ||
} else { | ||
// It's a value, create a fulfilled promise for it. | ||
promise = fulfilled(promiseOrValue); | ||
} | ||
return promise; | ||
} | ||
/** | ||
* Assimilate an untrusted thenable by introducing a trusted middle man. | ||
* Not a perfect strategy, but possibly the best we can do. | ||
* IMPORTANT: This is the only place when.js should ever call an untrusted | ||
* thenable's then() on an. Don't expose the return value to the untrusted thenable | ||
* | ||
* @param {*} thenable | ||
* @param {function} thenable.then | ||
* @returns {Promise} | ||
*/ | ||
function assimilate(thenable) { | ||
var d = defer(); | ||
// TODO: Enqueue this for future execution in 2.0 | ||
try { | ||
thenable.then( | ||
function(value) { d.resolve(value); }, | ||
function(reason) { d.reject(reason); }, | ||
function(update) { d.progress(update); } | ||
); | ||
} catch(e) { | ||
d.reject(e); | ||
} | ||
return d.promise; | ||
} | ||
/** | ||
* 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 | ||
* @param {*} promiseOrValue the rejected value of the returned {@link Promise} | ||
* @return {Promise} rejected {@link Promise} | ||
*/ | ||
function reject(promiseOrValue) { | ||
return when(promiseOrValue, rejected); | ||
} | ||
/** | ||
* Trusted Promise constructor. A Promise created from this constructor is | ||
@@ -148,14 +70,2 @@ * a trusted when.js promise. Any other duck-typed promise is considered | ||
/** | ||
* Register a callback that will be called when a promise is | ||
* fulfilled or rejected. Optionally also register a progress handler. | ||
* Shortcut for .then(onFulfilledOrRejected, onFulfilledOrRejected, onProgress) | ||
* @param {function?} [onFulfilledOrRejected] | ||
* @param {function?} [onProgress] | ||
* @return {Promise} | ||
*/ | ||
always: function(onFulfilledOrRejected, onProgress) { | ||
return this.then(onFulfilledOrRejected, onFulfilledOrRejected, onProgress); | ||
}, | ||
/** | ||
* Register a rejection handler. Shortcut for .then(undefined, onRejected) | ||
@@ -170,2 +80,22 @@ * @param {function?} 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 | ||
* @returns {Promise} | ||
*/ | ||
ensure: function(onFulfilledOrRejected) { | ||
var self = this; | ||
return this.then(injectHandler, injectHandler).yield(self); | ||
function injectHandler() { | ||
return resolve(onFulfilledOrRejected()); | ||
} | ||
}, | ||
/** | ||
* Shortcut for .then(function() { return value; }) | ||
@@ -198,2 +128,10 @@ * @param {*} value | ||
}); | ||
}, | ||
/** | ||
* Shortcut for .then(onFulfilledOrRejected, onFulfilledOrRejected) | ||
* @deprecated | ||
*/ | ||
always: function(onFulfilledOrRejected, onProgress) { | ||
return this.then(onFulfilledOrRejected, onFulfilledOrRejected, onProgress); | ||
} | ||
@@ -203,186 +141,157 @@ }; | ||
/** | ||
* Create an already-resolved promise for the supplied value | ||
* @private | ||
* | ||
* @param {*} value | ||
* @return {Promise} fulfilled promise | ||
* 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 | ||
* @param {*} value | ||
* @return {Promise} | ||
*/ | ||
function fulfilled(value) { | ||
var p = new Promise(function(onFulfilled) { | ||
try { | ||
return resolve(typeof onFulfilled == 'function' ? onFulfilled(value) : value); | ||
} catch(e) { | ||
return rejected(e); | ||
} | ||
function resolve(value) { | ||
return promise(function(resolve) { | ||
resolve(value); | ||
}); | ||
return p; | ||
} | ||
/** | ||
* Create an already-rejected {@link Promise} with the supplied | ||
* rejection reason. | ||
* @private | ||
* | ||
* @param {*} reason | ||
* @return {Promise} rejected promise | ||
* 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 | ||
* @param {*} promiseOrValue the rejected value of the returned {@link Promise} | ||
* @return {Promise} rejected {@link Promise} | ||
*/ | ||
function rejected(reason) { | ||
var p = new Promise(function(_, onRejected) { | ||
try { | ||
return resolve(typeof onRejected == 'function' ? onRejected(reason) : rejected(reason)); | ||
} catch(e) { | ||
return rejected(e); | ||
} | ||
}); | ||
return p; | ||
function reject(promiseOrValue) { | ||
return when(promiseOrValue, rejected); | ||
} | ||
/** | ||
* Creates a new, Deferred with fully isolated resolver and promise parts, | ||
* Creates a new Deferred with fully isolated resolver and promise parts, | ||
* either or both of which may be given out safely to consumers. | ||
* The Deferred itself has the full API: resolve, reject, progress, and | ||
* then. The resolver has resolve, reject, and progress. The promise | ||
* The resolver has resolve, reject, and progress. The promise | ||
* only has then. | ||
* | ||
* @return {Deferred} | ||
* @return {{ | ||
* promise: Promise, | ||
* resolver: { | ||
* resolve: function:Promise, | ||
* reject: function:Promise, | ||
* notify: function:Promise | ||
* }}} | ||
*/ | ||
function defer() { | ||
var deferred, promise, handlers, progressHandlers, | ||
_then, _notify, _resolve; | ||
var deferred, pending, resolved; | ||
/** | ||
* The promise for the new deferred | ||
* @type {Promise} | ||
*/ | ||
promise = new Promise(then); | ||
/** | ||
* The full Deferred object, with {@link Promise} and {@link Resolver} parts | ||
* @class Deferred | ||
* @name Deferred | ||
*/ | ||
// Optimize object shape | ||
deferred = { | ||
then: then, // DEPRECATED: use deferred.promise.then | ||
resolve: promiseResolve, | ||
reject: promiseReject, | ||
progress: promiseNotify, // DEPRECATED: use deferred.notify | ||
notify: promiseNotify, | ||
promise: promise, | ||
resolver: { | ||
resolve: promiseResolve, | ||
reject: promiseReject, | ||
progress: promiseNotify, // DEPRECATED: use deferred.notify | ||
notify: promiseNotify | ||
} | ||
promise: undef, resolve: undef, reject: undef, notify: undef, | ||
resolver: { resolve: undef, reject: undef, notify: undef } | ||
}; | ||
handlers = []; | ||
progressHandlers = []; | ||
deferred.promise = pending = promise(makeDeferred); | ||
/** | ||
* Pre-resolution then() that adds the supplied callback, errback, and progback | ||
* functions to the registered listeners | ||
* @private | ||
* | ||
* @param {function?} [onFulfilled] resolution handler | ||
* @param {function?} [onRejected] rejection handler | ||
* @param {function?} [onProgress] progress handler | ||
*/ | ||
_then = function(onFulfilled, onRejected, onProgress) { | ||
var deferred, progressHandler; | ||
return deferred; | ||
deferred = defer(); | ||
function makeDeferred(resolvePending, rejectPending, notifyPending) { | ||
deferred.resolve = deferred.resolver.resolve = function(value) { | ||
if(resolved) { | ||
return resolve(value); | ||
} | ||
resolved = true; | ||
resolvePending(value); | ||
return pending; | ||
}; | ||
progressHandler = typeof onProgress === 'function' | ||
? function(update) { | ||
try { | ||
// Allow progress handler to transform progress event | ||
deferred.notify(onProgress(update)); | ||
} catch(e) { | ||
// Use caught value as progress | ||
deferred.notify(e); | ||
} | ||
deferred.reject = deferred.resolver.reject = function(reason) { | ||
if(resolved) { | ||
return resolve(rejected(reason)); | ||
} | ||
: function(update) { deferred.notify(update); }; | ||
resolved = true; | ||
rejectPending(reason); | ||
return pending; | ||
}; | ||
handlers.push(function(promise) { | ||
promise.then(onFulfilled, onRejected) | ||
.then(deferred.resolve, deferred.reject, progressHandler); | ||
}); | ||
deferred.notify = deferred.resolver.notify = function(update) { | ||
notifyPending(update); | ||
return update; | ||
}; | ||
} | ||
} | ||
progressHandlers.push(progressHandler); | ||
/** | ||
* Creates a new promise whose fate is determined by resolver. | ||
* @private (for now) | ||
* @param {function} resolver function(resolve, reject, notify) | ||
* @returns {Promise} promise whose fate is determine by resolver | ||
*/ | ||
function promise(resolver) { | ||
var value, handlers = []; | ||
return deferred.promise; | ||
}; | ||
// Call the provider resolver to seal the promise's fate | ||
try { | ||
resolver(promiseResolve, promiseReject, promiseNotify); | ||
} catch(e) { | ||
promiseReject(e); | ||
} | ||
/** | ||
* Issue a progress event, notifying all progress listeners | ||
* @private | ||
* @param {*} update progress event payload to pass to all listeners | ||
*/ | ||
_notify = function(update) { | ||
processQueue(progressHandlers, update); | ||
return update; | ||
}; | ||
// Return the promise | ||
return new Promise(then); | ||
/** | ||
* Transition from pre-resolution state to post-resolution state, notifying | ||
* all listeners of the resolution or rejection | ||
* @private | ||
* @param {*} value the value of this deferred | ||
* Register handlers for this promise. | ||
* @param [onFulfilled] {Function} fulfillment handler | ||
* @param [onRejected] {Function} rejection handler | ||
* @param [onProgress] {Function} progress handler | ||
* @return {Promise} new Promise | ||
*/ | ||
_resolve = function(value) { | ||
// Replace _then with one that directly notifies with the result. | ||
_then = value.then; | ||
// Replace _resolve so that this Deferred can only be resolved once | ||
_resolve = resolve; | ||
// Make _progress a noop, to disallow progress for the resolved promise. | ||
_notify = identity; | ||
// Notify handlers | ||
processQueue(handlers, value); | ||
// Free progressHandlers array since we'll never issue progress events | ||
progressHandlers = handlers = undef; | ||
return value; | ||
}; | ||
return deferred; | ||
/** | ||
* Wrapper to allow _then to be replaced safely | ||
* @param {function?} [onFulfilled] resolution handler | ||
* @param {function?} [onRejected] rejection handler | ||
* @param {function?} [onProgress] progress handler | ||
* @return {Promise} new promise | ||
*/ | ||
function then(onFulfilled, onRejected, onProgress) { | ||
// TODO: Promises/A+ check typeof onFulfilled, onRejected, onProgress | ||
return _then(onFulfilled, onRejected, onProgress); | ||
return promise(function(resolve, reject, notify) { | ||
handlers | ||
// Call handlers later, after resolution | ||
? handlers.push(function(value) { | ||
value.then(onFulfilled, onRejected, onProgress) | ||
.then(resolve, reject, notify); | ||
}) | ||
// Call handlers soon, but not in the current stack | ||
: enqueue(function() { | ||
value.then(onFulfilled, onRejected, onProgress) | ||
.then(resolve, reject, notify); | ||
}); | ||
}); | ||
} | ||
/** | ||
* Wrapper to allow _resolve to be replaced | ||
* Transition from pre-resolution state to post-resolution state, notifying | ||
* all listeners of the ultimate fulfillment or rejection | ||
* @param {*|Promise} val resolution value | ||
*/ | ||
function promiseResolve(val) { | ||
return _resolve(resolve(val)); | ||
if(!handlers) { | ||
return; | ||
} | ||
value = coerce(val); | ||
scheduleHandlers(handlers, value); | ||
handlers = undef; | ||
} | ||
/** | ||
* Wrapper to allow _reject to be replaced | ||
* Reject this promise with the supplied reason, which will be used verbatim. | ||
* @param {*} reason reason for the rejection | ||
*/ | ||
function promiseReject(err) { | ||
return _resolve(rejected(err)); | ||
function promiseReject(reason) { | ||
promiseResolve(rejected(reason)); | ||
} | ||
/** | ||
* Wrapper to allow _notify to be replaced | ||
* Issue a progress event, notifying all progress listeners | ||
* @param {*} update progress event payload to pass to all listeners | ||
*/ | ||
function promiseNotify(update) { | ||
return _notify(update); | ||
if(handlers) { | ||
scheduleHandlers(handlers, progressing(update)); | ||
} | ||
} | ||
@@ -392,6 +301,117 @@ } | ||
/** | ||
* Determines if promiseOrValue is a promise or not. Uses the feature | ||
* test from http://wiki.commonjs.org/wiki/Promises/A to determine if | ||
* promiseOrValue is a promise. | ||
* Coerces x to a trusted Promise | ||
* | ||
* @private | ||
* @param {*} x thing to coerce | ||
* @returns {Promise} 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(x) { | ||
if(x instanceof Promise) { | ||
return x; | ||
} else if (x !== Object(x)) { | ||
return fulfilled(x); | ||
} | ||
return promise(function(resolve, reject, notify) { | ||
enqueue(function() { | ||
try { | ||
// We must check and assimilate in the same tick, but not the | ||
// current tick, careful only to access promiseOrValue.then once. | ||
var untrustedThen = x.then; | ||
if(typeof untrustedThen === 'function') { | ||
fcall(untrustedThen, x, resolve, reject, notify); | ||
} else { | ||
// It's a value, create a fulfilled wrapper | ||
resolve(fulfilled(x)); | ||
} | ||
} catch(e) { | ||
// Something went wrong, reject | ||
reject(e); | ||
} | ||
}); | ||
}); | ||
} | ||
/** | ||
* Create an already-fulfilled promise for the supplied value | ||
* @private | ||
* @param {*} value | ||
* @return {Promise} fulfilled promise | ||
*/ | ||
function fulfilled(value) { | ||
var self = new Promise(function (onFulfilled) { | ||
try { | ||
return typeof onFulfilled == 'function' | ||
? coerce(onFulfilled(value)) : self; | ||
} catch (e) { | ||
return rejected(e); | ||
} | ||
}); | ||
return self; | ||
} | ||
/** | ||
* Create an already-rejected promise with the supplied rejection reason. | ||
* @private | ||
* @param {*} reason | ||
* @return {Promise} rejected promise | ||
*/ | ||
function rejected(reason) { | ||
var self = new Promise(function (_, onRejected) { | ||
try { | ||
return typeof onRejected == 'function' | ||
? coerce(onRejected(reason)) : self; | ||
} catch (e) { | ||
return rejected(e); | ||
} | ||
}); | ||
return self; | ||
} | ||
/** | ||
* Create a progress promise with the supplied update. | ||
* @private | ||
* @param {*} update | ||
* @return {Promise} progress promise | ||
*/ | ||
function progressing(update) { | ||
var self = new Promise(function (_, __, onProgress) { | ||
try { | ||
return typeof onProgress == 'function' | ||
? progressing(onProgress(update)) : self; | ||
} catch (e) { | ||
return progressing(e); | ||
} | ||
}); | ||
return self; | ||
} | ||
/** | ||
* Schedule a task that will process a list of handlers | ||
* in the next queue drain run. | ||
* @private | ||
* @param {Array} handlers queue of handlers to execute | ||
* @param {*} value passed as the only arg to each handler | ||
*/ | ||
function scheduleHandlers(handlers, value) { | ||
enqueue(function() { | ||
var handler, i = 0; | ||
while (handler = handlers[i++]) { | ||
handler(value); | ||
} | ||
}); | ||
} | ||
/** | ||
* Determines if promiseOrValue is a promise or not | ||
* | ||
* @param {*} promiseOrValue anything | ||
@@ -417,4 +437,4 @@ * @returns {boolean} true if promiseOrValue is a {@link Promise} | ||
* @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. | ||
* resolved first, or will reject with an array of | ||
* (promisesOrValues.length - howMany) + 1 rejection reasons. | ||
*/ | ||
@@ -427,58 +447,52 @@ function some(promisesOrValues, howMany, onFulfilled, onRejected, onProgress) { | ||
var toResolve, toReject, values, reasons, deferred, fulfillOne, rejectOne, notify, len, i; | ||
return promise(resolveSome).then(onFulfilled, onRejected, onProgress); | ||
len = promisesOrValues.length >>> 0; | ||
function resolveSome(resolve, reject, notify) { | ||
var toResolve, toReject, values, reasons, fulfillOne, rejectOne, len, i; | ||
toResolve = Math.max(0, Math.min(howMany, len)); | ||
values = []; | ||
len = promisesOrValues.length >>> 0; | ||
toReject = (len - toResolve) + 1; | ||
reasons = []; | ||
toResolve = Math.max(0, Math.min(howMany, len)); | ||
values = []; | ||
deferred = defer(); | ||
toReject = (len - toResolve) + 1; | ||
reasons = []; | ||
// No items in the input, resolve immediately | ||
if (!toResolve) { | ||
deferred.resolve(values); | ||
// No items in the input, resolve immediately | ||
if (!toResolve) { | ||
resolve(values); | ||
} else { | ||
notify = deferred.notify; | ||
} else { | ||
rejectOne = function(reason) { | ||
reasons.push(reason); | ||
if(!--toReject) { | ||
fulfillOne = rejectOne = noop; | ||
reject(reasons); | ||
} | ||
}; | ||
rejectOne = function(reason) { | ||
reasons.push(reason); | ||
if(!--toReject) { | ||
fulfillOne = rejectOne = noop; | ||
deferred.reject(reasons); | ||
} | ||
}; | ||
fulfillOne = function(val) { | ||
// This orders the values based on promise resolution order | ||
values.push(val); | ||
if (!--toResolve) { | ||
fulfillOne = rejectOne = noop; | ||
resolve(values); | ||
} | ||
}; | ||
fulfillOne = function(val) { | ||
// This orders the values based on promise resolution order | ||
// Another strategy would be to use the original position of | ||
// the corresponding promise. | ||
values.push(val); | ||
if (!--toResolve) { | ||
fulfillOne = rejectOne = noop; | ||
deferred.resolve(values); | ||
for(i = 0; i < len; ++i) { | ||
if(i in promisesOrValues) { | ||
when(promisesOrValues[i], fulfiller, rejecter, notify); | ||
} | ||
} | ||
}; | ||
} | ||
for(i = 0; i < len; ++i) { | ||
if(i in promisesOrValues) { | ||
when(promisesOrValues[i], fulfiller, rejecter, notify); | ||
} | ||
function rejecter(reason) { | ||
rejectOne(reason); | ||
} | ||
} | ||
return deferred.promise.then(onFulfilled, onRejected, onProgress); | ||
function rejecter(reason) { | ||
rejectOne(reason); | ||
function fulfiller(val) { | ||
fulfillOne(val); | ||
} | ||
} | ||
function fulfiller(val) { | ||
fulfillOne(val); | ||
} | ||
}); | ||
@@ -541,3 +555,3 @@ } | ||
* | ||
* @param {Array|Promise} promise array of anything, may contain a mix | ||
* @param {Array|Promise} array array of anything, may contain a mix | ||
* of {@link Promise}s and values | ||
@@ -549,39 +563,39 @@ * @param {function} mapFunc mapping function mapFunc(value) which may return | ||
*/ | ||
function map(promise, mapFunc) { | ||
return when(promise, function(array) { | ||
var results, len, toResolve, resolve, i, d; | ||
function map(array, mapFunc) { | ||
return when(array, function(array) { | ||
// Since we know the resulting length, we can preallocate the results | ||
// array to avoid array expansions. | ||
toResolve = len = array.length >>> 0; | ||
results = []; | ||
d = defer(); | ||
return promise(resolveMap); | ||
if(!toResolve) { | ||
d.resolve(results); | ||
} else { | ||
function resolveMap(resolve, reject, notify) { | ||
var results, len, toResolve, resolveOne, i; | ||
resolve = function resolveOne(item, i) { | ||
when(item, mapFunc).then(function(mapped) { | ||
results[i] = mapped; | ||
// Since we know the resulting length, we can preallocate the results | ||
// array to avoid array expansions. | ||
toResolve = len = array.length >>> 0; | ||
results = []; | ||
if(!--toResolve) { | ||
d.resolve(results); | ||
if(!toResolve) { | ||
resolve(results); | ||
} else { | ||
resolveOne = function(item, i) { | ||
when(item, mapFunc).then(function(mapped) { | ||
results[i] = mapped; | ||
if(!--toResolve) { | ||
resolve(results); | ||
} | ||
}, reject, notify); | ||
}; | ||
// 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; | ||
} | ||
}, d.reject); | ||
}; | ||
// Since mapFunc may be async, get all invocations of it into flight | ||
for(i = 0; i < len; i++) { | ||
if(i in array) { | ||
resolve(array[i], i); | ||
} else { | ||
--toResolve; | ||
} | ||
} | ||
} | ||
return d.promise; | ||
}); | ||
@@ -604,3 +618,3 @@ } | ||
function reduce(promise, reduceFunc /*, initialValue */) { | ||
var args = slice.call(arguments, 1); | ||
var args = fcall(slice, arguments, 1); | ||
@@ -626,47 +640,26 @@ return when(promise, function(array) { | ||
/** | ||
* Ensure that resolution of promiseOrValue will trigger resolver with the | ||
* value or reason of promiseOrValue, or instead with resolveValue if it is provided. | ||
* | ||
* @param promiseOrValue | ||
* @param {Object} resolver | ||
* @param {function} resolver.resolve | ||
* @param {function} resolver.reject | ||
* @param {*} [resolveValue] | ||
* @returns {Promise} | ||
*/ | ||
function chain(promiseOrValue, resolver, resolveValue) { | ||
var useResolveValue = arguments.length > 2; | ||
// | ||
// Utilities, etc. | ||
// | ||
return when(promiseOrValue, | ||
function(val) { | ||
val = useResolveValue ? resolveValue : val; | ||
resolver.resolve(val); | ||
return val; | ||
}, | ||
function(reason) { | ||
resolver.reject(reason); | ||
return rejected(reason); | ||
}, | ||
function(update) { | ||
typeof resolver.notify === 'function' && resolver.notify(update); | ||
return update; | ||
} | ||
); | ||
} | ||
var reduceArray, slice, fcall, nextTick, handlerQueue, | ||
timeout, funcProto, call, arrayProto, undef; | ||
// | ||
// Utility functions | ||
// 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 = []; | ||
/** | ||
* Apply all functions in queue to value | ||
* @param {Array} queue array of functions to execute | ||
* @param {*} value argument passed to each function | ||
* Enqueue a task. If the queue is not currently scheduled to be | ||
* drained, schedule it. | ||
* @param {function} task | ||
*/ | ||
function processQueue(queue, value) { | ||
var handler, i = 0; | ||
while (handler = queue[i++]) { | ||
handler(value); | ||
function enqueue(task) { | ||
if(handlerQueue.push(task) === 1) { | ||
scheduleDrainQueue(); | ||
} | ||
@@ -676,49 +669,62 @@ } | ||
/** | ||
* Helper that checks arrayOfCallbacks to ensure that each element is either | ||
* a function, or null or undefined. | ||
* @private | ||
* @param {number} start index at which to start checking items in arrayOfCallbacks | ||
* @param {Array} arrayOfCallbacks array to check | ||
* @throws {Error} if any element of arrayOfCallbacks is something other than | ||
* a functions, null, or undefined. | ||
* Schedule the queue to be drained in the next tick. | ||
*/ | ||
function checkCallbacks(start, arrayOfCallbacks) { | ||
// TODO: Promises/A+ update type checking and docs | ||
var arg, i = arrayOfCallbacks.length; | ||
function scheduleDrainQueue() { | ||
nextTick(drainQueue); | ||
} | ||
while(i > start) { | ||
arg = arrayOfCallbacks[--i]; | ||
/** | ||
* Drain the handler queue entirely or partially, 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() { | ||
var task, i = 0; | ||
if (arg != null && typeof arg != 'function') { | ||
throw new Error('arg '+i+' must be a function'); | ||
} | ||
while(task = handlerQueue[i++]) { | ||
task(); | ||
} | ||
handlerQueue = []; | ||
} | ||
/** | ||
* No-Op function used in method replacement | ||
* @private | ||
*/ | ||
function noop() {} | ||
// | ||
// Capture function and array utils | ||
// | ||
/*global setImmediate:true*/ | ||
slice = [].slice; | ||
// capture setTimeout to avoid being caught by fake timers used in time based tests | ||
timeout = setTimeout; | ||
nextTick = typeof setImmediate === 'function' | ||
? typeof window === 'undefined' | ||
? setImmediate | ||
: setImmediate.bind(window) | ||
: typeof process === 'object' | ||
? process.nextTick | ||
: function(task) { timeout(task, 0); }; | ||
// 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. | ||
reduceArray = [].reduce || | ||
// 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*/ | ||
// 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 | ||
var arr, args, reduced, len, i; | ||
i = 0; | ||
// This generates a jshint warning, despite being valid | ||
// "Missing 'new' prefix when invoking a constructor." | ||
// See https://github.com/jshint/jshint/issues/392 | ||
arr = Object(this); | ||
@@ -751,3 +757,2 @@ len = arr.length >>> 0; | ||
for(;i < len; ++i) { | ||
// Skip holes | ||
if(i in arr) { | ||
@@ -761,2 +766,30 @@ reduced = reduceFunc(reduced, arr[i], i, arr); | ||
// | ||
// Utility functions | ||
// | ||
/** | ||
* Helper that checks arrayOfCallbacks to ensure that each element is either | ||
* a function, or null or undefined. | ||
* @private | ||
* @param {number} start index at which to start checking items in arrayOfCallbacks | ||
* @param {Array} arrayOfCallbacks array to check | ||
* @throws {Error} if any element of arrayOfCallbacks is something other than | ||
* a functions, null, or undefined. | ||
*/ | ||
function checkCallbacks(start, arrayOfCallbacks) { | ||
// TODO: Promises/A+ update type checking and docs | ||
var arg, i = arrayOfCallbacks.length; | ||
while(i > start) { | ||
arg = arrayOfCallbacks[--i]; | ||
if (arg != null && typeof arg != 'function') { | ||
throw new Error('arg '+i+' must be a function'); | ||
} | ||
} | ||
} | ||
function noop() {} | ||
function identity(x) { | ||
@@ -768,9 +801,4 @@ return x; | ||
}); | ||
})(typeof define == 'function' && define.amd | ||
? define | ||
: function (factory) { typeof exports === 'object' | ||
? (module.exports = factory()) | ||
: (this.when = factory()); | ||
} | ||
// Boilerplate for AMD, Node, and browser global | ||
})( | ||
typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(); } | ||
); |
Sorry, the diff of this file is not supported yet
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
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
91402
25
2179
104