Comparing version 1.3.0 to 1.4.0
@@ -39,3 +39,3 @@ /** @license MIT License (c) copyright B Cavalier & J Hann */ | ||
deferred.cancel = function() { | ||
delegate.reject(canceler(deferred)); | ||
return delegate.reject(canceler(deferred)); | ||
}; | ||
@@ -42,0 +42,0 @@ |
35
debug.js
@@ -72,2 +72,4 @@ /** @license MIT License (c) copyright B Cavalier & J Hann */ | ||
} | ||
return when.reject(err); | ||
} | ||
@@ -101,2 +103,16 @@ ); | ||
function wrapCallbacks(arguments) { | ||
var cb, args, len, i; | ||
args = []; | ||
for(i = 0, len = arguments.length; i < len; i++) { | ||
args[i] = typeof (cb = arguments[i]) == 'function' | ||
? wrapCallback(cb) | ||
: cb; | ||
} | ||
return args; | ||
} | ||
/** | ||
@@ -130,3 +146,3 @@ * Helper to form debug string for promises depending on their | ||
function whenDebug() { | ||
return debugPromise(when.apply(null, arguments)); | ||
return debugPromise(when.apply(null, wrapCallbacks(arguments))); | ||
} | ||
@@ -172,3 +188,2 @@ | ||
status = 'resolving'; | ||
// console.log(d.resolver.toString()); | ||
return origResolve.apply(undef, arguments); | ||
@@ -181,3 +196,2 @@ }; | ||
status = 'REJECTING'; | ||
// console.error(d.resolver.toString()); | ||
return origReject.apply(undef, arguments); | ||
@@ -193,3 +207,3 @@ }; | ||
function(v) { status = 'resolved'; return v; }, | ||
function(e) { status = 'REJECTED'; throw e; } | ||
function(e) { status = 'REJECTED'; return when.reject(e); } | ||
); | ||
@@ -203,14 +217,7 @@ | ||
d.then = d.promise.then = function(cb, eb, pb) { | ||
var args, p, id; | ||
id = d.id + '+'; | ||
var id = d.id + '>' + (++promiseId); | ||
args = []; | ||
var p = origThen.apply(null, wrapCallbacks(arguments)); | ||
if(arguments.length > 0) args[0] = wrapCallback(cb, id); | ||
if(arguments.length > 1) args[1] = wrapCallback(eb, id); | ||
if(arguments.length > 2) args[2] = wrapCallback(pb, id); | ||
var p = origThen.apply(null, args); | ||
p.id = id; | ||
@@ -232,3 +239,3 @@ p = beget(p); | ||
// has been setup, so the id can be logged. | ||
debugPromise(d.promise); | ||
//debugPromise(d.promise); | ||
@@ -235,0 +242,0 @@ // TODO: Should we still freeze these? |
{ | ||
"name": "when", | ||
"version": "1.3.0", | ||
"version": "1.4.0", | ||
"description": "A lightweight Promise and when() implementation, plus other async goodies.", | ||
@@ -30,5 +30,5 @@ "keywords": ["promises", "when", "async"], | ||
"devDependencies": { | ||
"buster": "~0.5" | ||
"buster": "~0.6" | ||
}, | ||
"main": "./when", | ||
"main": "when", | ||
"directories": { | ||
@@ -38,4 +38,4 @@ "test": "test" | ||
"scripts": { | ||
"test": "buster test -e node" | ||
"test": "./node_modules/buster/bin/buster-test -e node" | ||
} | ||
} |
265
README.md
@@ -1,19 +0,3 @@ | ||
Please Note: this project has moved from briancavalier/when to cujojs/when. | ||
Any existing forks have been automatically moved to cujojs/when. However, | ||
you'll need to update your clone and submodule remotes manually. | ||
# when.js [![Build Status](https://secure.travis-ci.org/cujojs/when.png)](http://travis-ci.org/cujojs/when) | ||
Update the url in your .git/config, and also .gitmodules for submodules: | ||
``` | ||
git://github.com/cujojs/when.git | ||
https://cujojs@github.com/cujojs/when.git | ||
``` | ||
Helpful link for updating submodules: | ||
[Git Submodules: Adding, Using, Removing, Updating](http://chrisjean.com/2009/04/20/git-submodules-adding-using-removing-and-updating/) | ||
---- | ||
[![Build Status](https://secure.travis-ci.org/cujojs/when.png)](http://travis-ci.org/cujojs/when) | ||
A lightweight [CommonJS](http://wiki.commonjs.org/wiki/Promises) [Promises/A](http://wiki.commonjs.org/wiki/Promises/A) and `when()` implementation. It also provides several other useful Promise-related concepts, such as joining and chaining, and has a robust unit test suite. | ||
@@ -28,28 +12,19 @@ | ||
### 1.3.0 | ||
### 1.4.0 | ||
* Fixed a deviation from the Promises/A spec where returning undefined from a callback or errback would cause the previous value to be forwarded. See [#31](https://github.com/cujojs/when/issues/31) | ||
* *This could be a breaking change* if you depended on this behavior. If you encounter problems, the solution is to ensure that your promise callbacks (registered either with `when()` or `.then()`) return what you intend, keeping in mind that not returning something is equivalent to returning `undefined`. | ||
* This change also restores compatibility with the promises returned by `jQuery.get()`, which seem to reject with themselves as the rejection value. See [issue #41](https://github.com/cujojs/when/issues/43) for more information and discussion. Thanks to [@KidkArolis](https://github.com/KidkArolis) for raising the issue. | ||
* Create a resolved promise: `when.resolve(value)` creates a resolved promise for `value`. See [API docs](when/blob/master/docs/api.md#whenresolve). | ||
* Resolve/reject return something useful: `deferred.resolve` and `deferred.reject` now return a promise for the fulfilled or rejected value. | ||
* Resolve a deferred with another promise: `deferred.resolve(promise)` - when `promise` resolves or rejects, so will `deferred`. | ||
### 1.2.0 | ||
[Full Changelog](https://github.com/cujojs/when/wiki/Changelog) | ||
* `promise.otherwise(errback)` as a shortcut for `promise.then(null, errback)`. See discussion [here](https://github.com/cujojs/when/issues/13) and [here](https://github.com/cujojs/when/issues/29). Thanks to [@jonnyreeves](https://github.com/jonnyreeves/) for suggesting the name "otherwise". | ||
* [when/debug](https://github.com/cujojs/when/wiki/when-debug) now detects exceptions that typically represent coding errors, such as SyntaxError, ReferenceError, etc. and propagates them to the host environment. In other words, you'll get a very loud stack trace. | ||
Docs & Examples | ||
=============== | ||
### 1.1.1 | ||
[API docs](when/blob/master/docs/api.md#api) | ||
* Updated [wiki](https://github.com/cujojs/when/wiki) map/reduce examples, and added simple promise forwarding example | ||
* Fix for calling `when.any()` without a callback ([#33](https://github.com/cujojs/when/issues/33)) | ||
* Fix version number in `when.js` source ([#36](https://github.com/cujojs/when/issues/36)) | ||
[More info on the wiki](https://github.com/cujojs/when/wiki) | ||
### 1.1.0 | ||
[Examples](https://github.com/cujojs/when/wiki/Examples) | ||
* `when.all/any/some/map/reduce` can all now accept a promise for an array in addition to an actual array as input. This allows composing functions to do interesting things like `when.reduce(when.map(...))` | ||
* `when.reject(promiseOrValue)` that returns a new, rejected promise. | ||
* `promise.always(callback)` as a shortcut for `promise.then(callback, callback)` | ||
* **Highly experimental** [when/debug](https://github.com/cujojs/when/wiki/when-debug) module: a drop-in replacement for the main `when` module that enables debug logging for promises created or consumed by when.js | ||
[Full Changelog](https://github.com/cujojs/when/wiki/Changelog) | ||
Quick Start | ||
@@ -80,3 +55,3 @@ =========== | ||
1. `npm install git://github.com/cujojs/when` (**NOTE:** npm seems to require a url that starts with "git" rather than http or https) | ||
1. `npm install when` | ||
1. `var when = require('when');` | ||
@@ -89,218 +64,2 @@ | ||
Docs & Examples | ||
=============== | ||
See the API section below, and the [wiki for more detailed docs](https://github.com/cujojs/when/wiki) and [examples](https://github.com/cujojs/when/wiki/Examples) | ||
API | ||
=== | ||
when() | ||
------ | ||
Register a handler for a promise or immediate value: | ||
```javascript | ||
when(promiseOrValue, callback, errback, progressback) | ||
// Always returns a promise, so can be chained: | ||
when(promiseOrValue, callback, errback, progressback).then(anotherCallback, anotherErrback, anotherProgressback) | ||
``` | ||
**Getting an already-resolved Promise** | ||
You can also use `when()` to get an already-resolved promise for a value, similarly to using `when.reject()` to get a rejected promise (see below): | ||
```javascript | ||
var resolved = when(anything); | ||
``` | ||
when.defer() | ||
------------ | ||
Create a new Deferred containing separate `promise` and `resolver` parts: | ||
```javascript | ||
var deferred = when.defer(); | ||
var promise = deferred.promise; | ||
var resolver = deferred.resolver; | ||
``` | ||
**Promise API** | ||
```javascript | ||
// var promise = deferred.promise; | ||
// then() | ||
// Main promise API | ||
// Register callback, errback, and/or progressback | ||
promise.then(callback, errback, progressback); | ||
``` | ||
**Extended Promise API** | ||
Convenience methods that are not part of the Promises/A proposal. | ||
```js | ||
// always() | ||
// Register an alwaysback that will be called when the promise resolves or rejects | ||
promise.always(alwaysback [, progressback]); | ||
// otherwise() | ||
// Convenience method to register only an errback | ||
promise.otherwise(errback); | ||
``` | ||
**Resolver API** | ||
```javascript | ||
// var resolver = deferred.resolver; | ||
resolver.resolve(value); | ||
resolver.reject(err); | ||
resolver.progress(update); | ||
``` | ||
The deferred has the full `promise` + `resolver` API: | ||
```javascript | ||
deferred.then(callback, errback, progressback); | ||
deferred.resolve(value); | ||
deferred.reject(reason); | ||
deferred.progress(update); | ||
``` | ||
when.reject() | ||
------------- | ||
```javascript | ||
var rejected = when.reject(anything); | ||
``` | ||
Return a rejected promise for the supplied promiseOrValue. If promiseOrValue is a value, it will be the rejection value of the returned promise. If promiseOrValue is a promise, its completion value will be the rejected value of the returned promise. | ||
This can be useful in situations where you need to reject a promise *without* throwing an exception. For example, it allows you to propagate a rejection with the value of another promise. | ||
```javascript | ||
when(doSomething(), | ||
handleSuccess, | ||
function(error) { | ||
// doSomething failed, but we want to do some processing on the error | ||
// to return something more useful to the caller. | ||
// This allows processError to return either a value or a promise. | ||
return when.reject(processError(e)); | ||
} | ||
); | ||
``` | ||
when.isPromise() | ||
---------------- | ||
```javascript | ||
var is = when.isPromise(anything); | ||
``` | ||
Return true if `anything` is truthy and implements the then() promise API. Note that this will return true for both a deferred (i.e. `when.defer()`), and a `deferred.promise` since both implement the promise API. | ||
when.some() | ||
----------- | ||
```javascript | ||
when.some(promisesOrValues, howMany, callback, errback, progressback) | ||
``` | ||
Return a promise that will resolve when `howMany` of the supplied `promisesOrValues` have resolved. The resolution value of the returned promise will be an array of length `howMany` containing the resolutions values of the triggering `promisesOrValues`. | ||
when.all() | ||
---------- | ||
```javascript | ||
when.all(promisesOrValues, callback, errback, progressback) | ||
``` | ||
Return a promise that will resolve only once *all* the supplied `promisesOrValues` have resolved. The resolution value of the returned promise will be an array containing the resolution values of each of the `promisesOrValues`. | ||
when.any() | ||
---------- | ||
```javascript | ||
when.any(promisesOrValues, callback, errback, progressback) | ||
``` | ||
Return a promise that will resolve when any one of the supplied `promisesOrValues` has resolved. The resolution value of the returned promise will be the resolution value of the triggering `promiseOrValue`. | ||
when.chain() | ||
------------ | ||
```javascript | ||
when.chain(promiseOrValue, resolver, optionalValue) | ||
``` | ||
Ensure that resolution of `promiseOrValue` will complete `resolver` with the completion value of `promiseOrValue`, or instead with `optionalValue` if it is provided. | ||
Returns a new promise that will complete when `promiseOrValue` is completed, with the completion value of `promiseOrValue`, or instead with `optionalValue` if it is provided. | ||
**Note:** If `promiseOrValue` is not an immediate value, it can be anything that supports the promise API (i.e. `then()`), so you can pass a `deferred` as well. Similarly, `resolver` can be anything that supports the resolver API (i.e. `resolve()`, `reject()`), so a `deferred` will work there, too. | ||
when.map() | ||
---------- | ||
```javascript | ||
when.map(promisesOrValues, mapFunc) | ||
``` | ||
Traditional map function, similar to `Array.prototype.map()`, but allows input to contain promises and/or values, and mapFunc may return either a value or a promise. | ||
The map function should have the signature: | ||
```javascript | ||
mapFunc(item) | ||
``` | ||
Where: | ||
* `item` is a fully resolved value of a promise or value in `promisesOrValues` | ||
when.reduce() | ||
------------- | ||
```javascript | ||
when.reduce(promisesOrValues, reduceFunc, initialValue) | ||
``` | ||
Traditional reduce function, similar to `Array.prototype.reduce()`, but input may contain promises and/or values, and reduceFunc may return either a value or a promise, *and* initialValue may be a promise for the starting value. | ||
The reduce function should have the signature: | ||
```javascript | ||
reduceFunc(currentValue, nextItem, index, total) | ||
``` | ||
Where: | ||
* `currentValue` is the current accumulated reduce value | ||
* `nextItem` is the fully resolved value of the promise or value at `index` in `promisesOrValues` | ||
* `index` the *basis* of `nextItem` ... practically speaking, this is the array index of the promiseOrValue corresponding to `nextItem` | ||
* `total` is the total number of items in `promisesOrValues` | ||
when/apply | ||
---------- | ||
```javascript | ||
function functionThatAcceptsMultipleArgs(array) { | ||
// ... | ||
} | ||
var functionThatAcceptsAnArray = apply(functionThatAcceptsMultipleArgs); | ||
``` | ||
Helper that allows using callbacks that take multiple args, instead of an array, with `when.all/some/map`: | ||
```javascript | ||
when.all(arrayOfPromisesOrValues, apply(functionThatAcceptsMultipleArgs)); | ||
``` | ||
[See the wiki](https://github.com/cujojs/when/wiki/when-apply) for more info and examples. | ||
Running the Unit Tests | ||
@@ -307,0 +66,0 @@ ====================== |
@@ -26,4 +26,4 @@ /** @license MIT License (c) copyright B Cavalier & J Hann */ | ||
* | ||
* // return a new promise that will timeout if we don't resolve/reject first | ||
* return timeout(d, 1000); | ||
* // return a new promise that will timeout if d doesn't resolve/reject first | ||
* return timeout(d.promise, 1000); | ||
* | ||
@@ -50,14 +50,14 @@ * @param promise anything - any promise or value that should trigger | ||
when(promise, deferred.resolve, deferred.reject); | ||
when(promise, | ||
function(value) { | ||
cancelTimeout(); | ||
deferred.resolve(value); | ||
}, | ||
function(reason) { | ||
cancelTimeout(); | ||
deferred.reject(reason); | ||
} | ||
); | ||
return deferred.then( | ||
function(value) { | ||
cancelTimeout(); | ||
return value; | ||
}, | ||
function(reason) { | ||
cancelTimeout(); | ||
throw reason; | ||
} | ||
); | ||
return deferred.promise; | ||
}; | ||
@@ -64,0 +64,0 @@ |
482
when.js
/** @license MIT License (c) copyright B Cavalier & J Hann */ | ||
/** | ||
* when | ||
* A lightweight CommonJS Promises/A and when() implementation | ||
* | ||
* when is part of the cujo.js family of libraries (http://cujojs.com/) | ||
@@ -12,27 +10,114 @@ * | ||
* | ||
* @version 1.3.0 | ||
* @version 1.4.0 | ||
*/ | ||
(function(define) { | ||
define(function() { | ||
define(function() { "use strict"; | ||
var freeze, reduceArray, slice, undef; | ||
// | ||
// Public API | ||
// | ||
when.defer = defer; | ||
when.reject = reject; | ||
when.isPromise = isPromise; | ||
when.defer = defer; // Create a deferred | ||
when.resolve = resolve; // Create a resolved promise | ||
when.reject = reject; // Create a rejected promise | ||
when.all = all; | ||
when.some = some; | ||
when.any = any; | ||
when.all = all; // Resolve a list of promises | ||
when.some = some; // Resolve a sub-set of promises | ||
when.any = any; // Resolve one promise in a list | ||
when.map = map; | ||
when.reduce = reduce; | ||
when.map = map; // Array.map() for promises | ||
when.reduce = reduce; // Array.reduce() for promises | ||
when.chain = chain; | ||
when.chain = chain; // Make a promise trigger another resolver | ||
/** Object.freeze */ | ||
when.isPromise = isPromise; // Determine if a thing is a promise | ||
/** | ||
* Register an observer for a promise or immediate value. | ||
* @function | ||
* @name when | ||
* @namespace | ||
* | ||
* @param promiseOrValue {*} | ||
* @param {Function} [callback] callback to be called when promiseOrValue is | ||
* successfully resolved. If promiseOrValue is an immediate value, callback | ||
* will be invoked immediately. | ||
* @param {Function} [errback] callback to be called when promiseOrValue is | ||
* rejected. | ||
* @param {Function} [progressHandler] callback to be called when progress updates | ||
* are issued for promiseOrValue. | ||
* @returns {Promise} a new {@link Promise} that will complete 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, callback, errback, progressHandler) { | ||
// Get a trusted promise for the input promiseOrValue, and then | ||
// register promise handlers | ||
return resolve(promiseOrValue).then(callback, errback, progressHandler); | ||
} | ||
/** | ||
* Returns promiseOrValue if promiseOrValue is a {@link Promise}, a new Promise if | ||
* promiseOrValue is a foreign promise, or a new, already-resolved {@link Promise} | ||
* whose resolution value is promiseOrValue if promiseOrValue is an immediate value. | ||
* @memberOf when | ||
* | ||
* @param promiseOrValue {*} | ||
* @returns Guaranteed to return a trusted Promise. If promiseOrValue is a when.js {@link Promise} | ||
* returns promiseOrValue, otherwise, returns a new, already-resolved, when.js {@link 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, deferred; | ||
if(promiseOrValue instanceof Promise) { | ||
// It's a when.js promise, so we trust it | ||
promise = promiseOrValue; | ||
} else { | ||
// It's not a when.js promise. | ||
// Check to see if it's a foreign promise or a value. | ||
if(isPromise(promiseOrValue)) { | ||
// It looks like a thenable, but we don't know where it came from, | ||
// so we don't trust its implementation entirely. Introduce a trusted | ||
// middleman when.js promise | ||
deferred = defer(); | ||
// IMPORTANT: This is the only place when.js should ever call .then() on | ||
// an untrusted promise. | ||
promiseOrValue.then(deferred.resolve, deferred.reject, deferred.progress); | ||
promise = deferred.promise; | ||
} else { | ||
// It's a value, not a promise. Create a resolved promise for it. | ||
promise = resolved(promiseOrValue); | ||
} | ||
} | ||
return promise; | ||
} | ||
/** | ||
* Returns a rejected promise for the supplied promiseOrValue. If | ||
* promiseOrValue is a value, it will be the rejection value of the | ||
* returned promise. If promiseOrValue is a promise, its | ||
* completion value will be the rejected value of the returned promise | ||
* @memberOf when | ||
* | ||
* @param promiseOrValue {*} the rejected value of the returned {@link Promise} | ||
* @return {Promise} rejected {@link Promise} | ||
*/ | ||
function reject(promiseOrValue) { | ||
return when(promiseOrValue, function(value) { | ||
return rejected(value); | ||
}); | ||
} | ||
/** | ||
* Object.freeze | ||
* @private | ||
*/ | ||
freeze = Object.freeze || function(o) { return o; }; | ||
@@ -44,4 +129,4 @@ | ||
* untrusted. | ||
* | ||
* @constructor | ||
* @name Promise | ||
*/ | ||
@@ -51,2 +136,11 @@ function Promise() {} | ||
Promise.prototype = freeze({ | ||
/** | ||
* Register a callback that will be called when a promise is | ||
* resolved or rejected. Optionally also register a progress handler. | ||
* Shortcut for .then(alwaysback, alwaysback, progback) | ||
* @memberOf Promise | ||
* @param alwaysback {Function} | ||
* @param progback {Function} | ||
* @return {Promise} | ||
*/ | ||
always: function(alwaysback, progback) { | ||
@@ -56,2 +150,8 @@ return this.then(alwaysback, alwaysback, progback); | ||
/** | ||
* Register a rejection handler. Shortcut for .then(null, errback) | ||
* @memberOf Promise | ||
* @param errback {Function} | ||
* @return {Promise} | ||
*/ | ||
otherwise: function(errback) { | ||
@@ -75,3 +175,3 @@ return this.then(undef, errback); | ||
try { | ||
return promise(callback ? callback(value) : value); | ||
return resolve(callback ? callback(value) : value); | ||
} catch(e) { | ||
@@ -99,3 +199,3 @@ return rejected(e); | ||
try { | ||
return errback ? promise(errback(reason)) : rejected(reason); | ||
return errback ? resolve(errback(reason)) : rejected(reason); | ||
} catch(e) { | ||
@@ -110,32 +210,15 @@ return rejected(e); | ||
/** | ||
* Returns a rejected promise for the supplied promiseOrValue. If | ||
* promiseOrValue is a value, it will be the rejection value of the | ||
* returned promise. If promiseOrValue is a promise, its | ||
* completion value will be the rejected value of the returned promise | ||
* | ||
* @param promiseOrValue {*} the rejected value of the returned {@link Promise} | ||
* | ||
* @return {Promise} rejected {@link Promise} | ||
*/ | ||
function reject(promiseOrValue) { | ||
return when(promiseOrValue, function(value) { | ||
return rejected(value); | ||
}); | ||
} | ||
/** | ||
* Creates a new, CommonJS compliant, Deferred with fully isolated | ||
* resolver and promise parts, either or both of which may be given out | ||
* safely to consumers. | ||
* 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 | ||
* only has then. | ||
* | ||
* @memberOf when | ||
* @function | ||
* | ||
* @returns {Deferred} | ||
* @return {Deferred} | ||
*/ | ||
function defer() { | ||
var deferred, promise, listeners, progressHandlers, _then, _progress, complete; | ||
var deferred, promise, resolver, listeners, progressHandlers, | ||
_then, _progress, _resolve; | ||
@@ -146,26 +229,24 @@ listeners = []; | ||
/** | ||
* Pre-resolution then() that adds the supplied callback, errback, and progback | ||
* functions to the registered listeners | ||
* | ||
* @private | ||
* | ||
* @param [callback] {Function} resolution handler | ||
* @param [errback] {Function} rejection handler | ||
* @param [progback] {Function} progress handler | ||
* | ||
* @throws {Error} if any argument is not null, undefined, or a Function | ||
* The full Deferred object, with {@link Promise} and {@link Resolver} parts | ||
* @class Deferred | ||
* @name Deferred | ||
*/ | ||
_then = function unresolvedThen(callback, errback, progback) { | ||
var deferred = defer(); | ||
deferred = {}; | ||
listeners.push(function(promise) { | ||
promise.then(callback, errback) | ||
.then(deferred.resolve, deferred.reject, deferred.progress); | ||
}); | ||
/** | ||
* The {@link Resolver} for this {@link Deferred} | ||
* @memberOf Deferred | ||
* @name resolver | ||
* @class Resolver | ||
*/ | ||
resolver = {}; | ||
progback && progressHandlers.push(progback); | ||
/** | ||
* The {@link Promise} for this {@link Deferred} | ||
* @memberOf Deferred | ||
* @name promise | ||
* @type {Promise} | ||
*/ | ||
promise = new Promise(); | ||
return deferred.promise; | ||
}; | ||
/** | ||
@@ -175,26 +256,28 @@ * Registers a handler for this {@link Deferred}'s {@link Promise}. Even though all arguments | ||
* Any other value will cause an Error to be thrown. | ||
* | ||
* @memberOf Promise | ||
* | ||
* @name then | ||
* @param [callback] {Function} resolution handler | ||
* @param [errback] {Function} rejection handler | ||
* @param [progback] {Function} progress handler | ||
* | ||
* @throws {Error} if any argument is not null, undefined, or a Function | ||
* @throw {Error} if any argument is not null, undefined, or a Function | ||
*/ | ||
function then(callback, errback, progback) { | ||
promise.then = deferred.then = function then(callback, errback, progback) { | ||
return _then(callback, errback, progback); | ||
} | ||
}; | ||
deferred.promise = freeze(promise); | ||
/** | ||
* Resolves this {@link Deferred}'s {@link Promise} with val as the | ||
* resolution value. | ||
* | ||
* @memberOf Resolver | ||
* | ||
* @param val anything | ||
* @param val {*|Promise} If val is anything but a Promise, resolves this | ||
* Deferred's Promise with val. If val is a Promise, puts this Deferred's | ||
* Promise into the same state as val. For example, if val is a rejected | ||
* promise, this Deferred will become rejected. | ||
* @return {Promise} a promise for the resolution value | ||
*/ | ||
function resolve(val) { | ||
complete(resolved(val)); | ||
} | ||
resolver.resolve = deferred.resolve = function resolve(val) { | ||
return _resolve(val); | ||
}; | ||
@@ -204,18 +287,8 @@ /** | ||
* reason. | ||
* | ||
* @memberOf Resolver | ||
* | ||
* @param err anything | ||
* @return {Promise} a promise for the rejection value | ||
*/ | ||
function reject(err) { | ||
complete(rejected(err)); | ||
} | ||
/** | ||
* @private | ||
* @param update | ||
*/ | ||
_progress = function(update) { | ||
var progress, i = 0; | ||
while (progress = progressHandlers[i++]) progress(update); | ||
resolver.reject = deferred.reject = function reject(err) { | ||
return _resolve(rejected(err)); | ||
}; | ||
@@ -226,22 +299,55 @@ | ||
* this {@link Deferred}'s {@link Promise} | ||
* | ||
* @memberOf Resolver | ||
* | ||
* @param update anything | ||
*/ | ||
function progress(update) { | ||
resolver.progress = deferred.progress = function progress(update) { | ||
_progress(update); | ||
} | ||
}; | ||
deferred.resolver = freeze(resolver); | ||
/** | ||
* Pre-resolution then() that adds the supplied callback, errback, and progback | ||
* functions to the registered listeners | ||
* @private | ||
* | ||
* @param [callback] {Function} resolution handler | ||
* @param [errback] {Function} rejection handler | ||
* @param [progback] {Function} progress handler | ||
* @throws {Error} if any argument is not null, undefined, or a Function | ||
*/ | ||
_then = function(callback, errback, progback) { | ||
var deferred = defer(); | ||
listeners.push(function(promise) { | ||
promise.then(callback, errback) | ||
.then(deferred.resolve, deferred.reject, deferred.progress); | ||
}); | ||
progback && progressHandlers.push(progback); | ||
return deferred.promise; | ||
}; | ||
/** | ||
* Issue a progress event, notifying all progress listeners | ||
* @private | ||
* @param update {*} progress event payload to pass to all listeners | ||
*/ | ||
_progress = function(update) { | ||
var progress, i = 0; | ||
while (progress = progressHandlers[i++]) progress(update); | ||
}; | ||
/** | ||
* Transition from pre-resolution state to post-resolution state, notifying | ||
* all listeners of the resolution or rejection | ||
* | ||
* @private | ||
* | ||
* @param completed {Promise} the completed value of this deferred | ||
*/ | ||
complete = function(completed) { | ||
_resolve = function(completed) { | ||
var listener, i = 0; | ||
completed = resolve(completed); | ||
// Replace _then with one that directly notifies with the result. | ||
@@ -253,3 +359,3 @@ _then = completed.then; | ||
// progress throw. | ||
complete = _progress = function alreadyCompleted() { | ||
_resolve = _progress = function alreadyResolved() { | ||
// TODO: Consider silently returning here so that parties who | ||
@@ -261,9 +367,3 @@ // have a reference to the resolver cannot tell that the promise | ||
// Free progressHandlers array since we'll never issue progress events | ||
// for this promise again now that it's completed | ||
progressHandlers = undef; | ||
// Notify listeners | ||
// Traverse all listeners registered directly with this Deferred | ||
while (listener = listeners[i++]) { | ||
@@ -273,39 +373,9 @@ listener(completed); | ||
listeners = []; | ||
// Free progressHandlers array since we'll never issue progress events | ||
// for this promise again now that it's completed | ||
progressHandlers = listeners = undef; | ||
return completed; | ||
}; | ||
/** | ||
* The full Deferred object, with both {@link Promise} and {@link Resolver} | ||
* parts | ||
* @class Deferred | ||
* @name Deferred | ||
*/ | ||
deferred = {}; | ||
// Promise and Resolver parts | ||
// Freeze Promise and Resolver APIs | ||
promise = new Promise(); | ||
promise.then = deferred.then = then; | ||
/** | ||
* The {@link Promise} for this {@link Deferred} | ||
* @memberOf Deferred | ||
* @name promise | ||
* @type {Promise} | ||
*/ | ||
deferred.promise = freeze(promise); | ||
/** | ||
* The {@link Resolver} for this {@link Deferred} | ||
* @memberOf Deferred | ||
* @name resolver | ||
* @class Resolver | ||
*/ | ||
deferred.resolver = freeze({ | ||
resolve: (deferred.resolve = resolve), | ||
reject: (deferred.reject = reject), | ||
progress: (deferred.progress = progress) | ||
}); | ||
return deferred; | ||
@@ -320,3 +390,2 @@ } | ||
* @param promiseOrValue anything | ||
* | ||
* @returns {Boolean} true if promiseOrValue is a {@link Promise} | ||
@@ -329,86 +398,5 @@ */ | ||
/** | ||
* Register an observer for a promise or immediate value. | ||
* | ||
* @function | ||
* @name when | ||
* @namespace | ||
* | ||
* @param promiseOrValue anything | ||
* @param {Function} [callback] callback to be called when promiseOrValue is | ||
* successfully resolved. If promiseOrValue is an immediate value, callback | ||
* will be invoked immediately. | ||
* @param {Function} [errback] callback to be called when promiseOrValue is | ||
* rejected. | ||
* @param {Function} [progressHandler] callback to be called when progress updates | ||
* are issued for promiseOrValue. | ||
* | ||
* @returns {Promise} a new {@link Promise} that will complete 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, callback, errback, progressHandler) { | ||
// Get a promise for the input promiseOrValue | ||
// See promise() | ||
var trustedPromise = promise(promiseOrValue); | ||
// Register promise handlers | ||
return trustedPromise.then(callback, errback, progressHandler); | ||
} | ||
/** | ||
* Returns promiseOrValue if promiseOrValue is a {@link Promise}, a new Promise if | ||
* promiseOrValue is a foreign promise, or a new, already-resolved {@link Promise} | ||
* whose resolution value is promiseOrValue if promiseOrValue is an immediate value. | ||
* | ||
* Note that this function is not safe to export since it will return its | ||
* input when promiseOrValue is a {@link Promise} | ||
* | ||
* @private | ||
* | ||
* @param promiseOrValue anything | ||
* | ||
* @returns Guaranteed to return a trusted Promise. If promiseOrValue is a when.js {@link Promise} | ||
* returns promiseOrValue, otherwise, returns a new, already-resolved, when.js {@link Promise} | ||
* whose resolution value is: | ||
* * the resolution value of promiseOrValue if it's a foreign promise, or | ||
* * promiseOrValue if it's a value | ||
*/ | ||
function promise(promiseOrValue) { | ||
var promise, deferred; | ||
if(promiseOrValue instanceof Promise) { | ||
// It's a when.js promise, so we trust it | ||
promise = promiseOrValue; | ||
} else { | ||
// It's not a when.js promise. Check to see if it's a foreign promise | ||
// or a value. | ||
deferred = defer(); | ||
if(isPromise(promiseOrValue)) { | ||
// It's a compliant promise, but we don't know where it came from, | ||
// so we don't trust its implementation entirely. Introduce a trusted | ||
// middleman when.js promise | ||
// IMPORTANT: This is the only place when.js should ever call .then() on | ||
// an untrusted promise. | ||
promiseOrValue.then(deferred.resolve, deferred.reject, deferred.progress); | ||
promise = deferred.promise; | ||
} else { | ||
// It's a value, not a promise. Create an already-resolved promise | ||
// for it. | ||
deferred.resolve(promiseOrValue); | ||
promise = deferred.promise; | ||
} | ||
} | ||
return promise; | ||
} | ||
/** | ||
* Return a promise that will resolve when howMany of the supplied promisesOrValues | ||
* have resolved. The resolution value of the returned promise will be an array of | ||
* length howMany containing the resolutions values of the triggering promisesOrValues. | ||
* | ||
* @memberOf when | ||
@@ -422,3 +410,2 @@ * | ||
* @param [progressHandler] | ||
* | ||
* @returns {Promise} | ||
@@ -432,3 +419,3 @@ */ | ||
var toResolve, results, ret, deferred, resolver, rejecter, handleProgress, len, i; | ||
var toResolve, results, deferred, resolver, rejecter, handleProgress, len, i; | ||
@@ -440,3 +427,2 @@ len = promisesOrValues.length >>> 0; | ||
deferred = defer(); | ||
ret = when(deferred, callback, errback, progressHandler); | ||
@@ -458,6 +444,2 @@ // Wrapper so that resolver can be replaced | ||
function complete() { | ||
resolver = rejecter = handleProgress = noop; | ||
} | ||
// No items in the input, resolve immediately | ||
@@ -468,2 +450,14 @@ if (!toResolve) { | ||
} else { | ||
deferred.promise.always(function complete() { | ||
resolver = rejecter = handleProgress = noop; | ||
}); | ||
// Rejecter for promises. Rejects returned promise | ||
// immediately, and overwrites rejecter var with a noop | ||
// once promise to cover case where n < promises.length. | ||
// TODO: Consider rejecting only when N (or promises.length - N?) | ||
// promises have been rejected instead of only one? | ||
rejecter = deferred.reject; | ||
handleProgress = deferred.progress; | ||
// Resolver for promises. Captures the value and resolves | ||
@@ -480,3 +474,2 @@ // the returned promise when toResolve reaches zero. | ||
if (!--toResolve) { | ||
complete(); | ||
deferred.resolve(results); | ||
@@ -486,14 +479,2 @@ } | ||
// Rejecter for promises. Rejects returned promise | ||
// immediately, and overwrites rejecter var with a noop | ||
// once promise to cover case where n < promises.length. | ||
// TODO: Consider rejecting only when N (or promises.length - N?) | ||
// promises have been rejected instead of only one? | ||
rejecter = function(err) { | ||
complete(); | ||
deferred.reject(err); | ||
}; | ||
handleProgress = deferred.progress; | ||
// TODO: Replace while with forEach | ||
@@ -507,3 +488,3 @@ for(i = 0; i < len; ++i) { | ||
return ret; | ||
return when(deferred, callback, errback, progressHandler); | ||
}); | ||
@@ -516,3 +497,2 @@ } | ||
* containing the resolution values of each of the promisesOrValues. | ||
* | ||
* @memberOf when | ||
@@ -525,3 +505,2 @@ * | ||
* @param [progressHandler] {Function} | ||
* | ||
* @returns {Promise} | ||
@@ -547,3 +526,2 @@ */ | ||
* value of the triggering promiseOrValue. | ||
* | ||
* @memberOf when | ||
@@ -556,3 +534,2 @@ * | ||
* @param [progressHandler] {Function} | ||
* | ||
* @returns {Promise} | ||
@@ -580,3 +557,2 @@ */ | ||
* either a {@link Promise} or value | ||
* | ||
* @returns {Promise} a {@link Promise} that will resolve to an array containing | ||
@@ -628,3 +604,2 @@ * the mapped output values. | ||
* be a {@link Promise} for the starting value. | ||
* | ||
* @memberOf when | ||
@@ -639,3 +614,2 @@ * | ||
* @param initialValue starting value, or a {@link Promise} for the starting value | ||
* | ||
* @returns {Promise} that will resolve to the final reduced value | ||
@@ -665,8 +639,4 @@ */ | ||
// Skip promisesOrValues, since it will be used as 'this' in the call | ||
// to the actual reduce engine below. | ||
// Wrap the supplied reduceFunc with one that handles promises and then | ||
// delegates to the supplied. | ||
args = [ | ||
@@ -690,3 +660,2 @@ function (current, val, i) { | ||
* value of promiseOrValue, or instead with resolveValue if it is provided. | ||
* | ||
* @memberOf when | ||
@@ -697,3 +666,2 @@ * | ||
* @param [resolveValue] anything | ||
* | ||
* @returns {Promise} | ||
@@ -706,10 +674,5 @@ */ | ||
function(val) { | ||
if(useResolveValue) val = resolveValue; | ||
resolver.resolve(val); | ||
return val; | ||
return resolver.resolve(useResolveValue ? resolveValue : val); | ||
}, | ||
function(e) { | ||
resolver.reject(e); | ||
return rejected(e); | ||
}, | ||
resolver.reject, | ||
resolver.progress | ||
@@ -726,3 +689,2 @@ ); | ||
* a function, or null or undefined. | ||
* | ||
* @private | ||
@@ -738,3 +700,3 @@ * | ||
arg = arrayOfCallbacks[--i]; | ||
if (arg != null && typeof arg != 'function') throw new Error('callback is not a function'); | ||
if (arg != null && typeof arg != 'function') throw new Error('arg '+i+' must be a function'); | ||
} | ||
@@ -741,0 +703,0 @@ } |
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
42062
1106
85