Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

466 lines (321 sloc) 15.132 kb

API

  1. when
  2. Deferred
  3. Promise
  4. Resolver
  5. Creating promises
  6. Joining promises
  7. Higher order operations
  8. Timed promises
  9. Concurrency
  10. Helpers
  11. Configuration

when()

when(promiseOrValue, callback, errback, progressback)

Observe a promise or immediate value.

// Returns a promise for the result of the callback or errback
var promise = when(promiseOrValue, callback, errback);

// Always returns a promise, so it is guaranteed to be chainable:
when(promiseOrValue, callback, errback, progressback).then(anotherCallback, anotherErrback, anotherProgressback);

// All parameters except the first are optional
// For example, you can register only a callback
when(promiseOrValue, callback);

when() can observe any promise that provides a Promises/A-like .then() method, even promises that aren't fully Promises/A compliant, such as jQuery's Deferred. It will assimilate such promises and make them behave like Promises/A.

Read more about when() here

Deferred

A deferred has the full promise + resolver API:

deferred.then(callback, errback, progressback);
deferred.resolve(promiseOrValue);
deferred.reject(reason);
deferred.progress(update);

And separate promise and resolver parts that can be safely given out to calling code.

var promise = deferred.promise;
var resolver = deferred.resolver;

Promise

// Get a deferred promise
var promise = deferred.promise;

// Or a resolved promise
var promise = when.resolve(promiseOrValue);

// Or a rejected promise
var promise = when.reject(value);

Main Promise API

// then()
// Main promise API
// Register callback, errback, and/or progressback
var newPromise = promise.then(callback, errback, progressback);

Registers new success, error, and/or progress handlers with a promise. All parameters are optional. As per the Promises/A spec, returns a new promise that will be resolved with the result of callback if promise is fulfilled, or with the result of errback if promise is rejected.

A promise makes the following guarantees about handlers registered in the same call to .then():

  1. Only one of callback or errback will be called, never both.
  2. callback and errback will never be called more than once.
  3. progressback may be called multiple times.

Extended Promise API

Convenience methods that are not part of the Promises/A proposal. These are simply shortcuts for using .then().

always()

promise.always(alwaysback [, progressback]);

Register an alwaysback that will be called when the promise resolves or rejects

otherwise()

promise.otherwise(errback);

Register only an errback

Resolver

var resolver = deferred.resolver;
resolver.resolve(promiseOrValue);
resolver.reject(err);
resolver.progress(update);

Creating promises

when.defer()

var deferred = when.defer();

Create a new Deferred that can resolved at a later time.

when.resolve()

var resolved = when.resolve(promiseOrValue);

Create a resolved promise for the supplied promiseOrValue. If promiseOrValue is a value, it will be the resolution value of the returned promise. Returns promiseOrValue if it's a trusted promise. If promiseOrValue is a foreign promise, returns a promise in the same state (resolved or rejected) and with the same value as promiseOrValue.

when.reject()

var rejected = when.reject(promiseOrValue);

Create 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.

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()

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.

Joining promises

when.all()

var promise = 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()

var promise = 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.some()

var promise = 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.chain()

var promise = 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.

Higher order operations

when.map()

var promise = 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:

mapFunc(item)

Where:

  • item is a fully resolved value of a promise or value in promisesOrValues

when.reduce()

var promise = 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:

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

Timed promises

when/delay

var delayed = delay(promiseOrValue, milliseconds);

Create a promise that resolves after a delay, or after a delay following the resolution of another promise.

var delay, delayed;

delay = require('when/delay');

// delayed is an unresolved promise that will become resolved
// in 1 second with the value 123
delayed = delay(123, 1000)

// delayed is an unresolved promise that will become resolved
// 1 second after anotherPromise resolves, or will become rejected
// *immediately* after anotherPromise rejects.
delayed = delay(anotherPromise, 1000);

More when/delay examples on the wiki

when/timeout

var timed = timeout(promiseOrValue, milliseconds);

Create a promise that will reject after a timeout if promiseOrValue does not resolved or rejected beforehand. If promiseOrValue is a value, the returned promise will resolve immediately. More interestingly, if promiseOrValue is a promise, if it resolved before the timeout period, the returned promise will resolve. If it doesn't, the returned promise will reject.

var timeout, timed;

timeout = require('when/timeout');

// timed will reject after 5 seconds unless anotherPromise resolves beforehand.
timed = timeout(anotherPromise, 5000);

More when/timeout examples on the wiki

Concurrency

These modules allow you to execute tasks in series or parallel. Each module takes an Array of task functions (or a promise for an Array), executes the tasks, and returns a promise that resolves when all the tasks have completed.

when/sequence

var sequence, resultsPromise;

sequence = require('when/sequence');

resultsPromise = sequence(arrayOfTasks, arg1, arg2 /*, ... */);

Run an array of tasks in sequence, without overlap. Each task will be called with the arguments passed to when.sequence(), and each may return a promise or a value.

When all tasks have completed, the returned promise will resolve to an array containing the result of each task at the corresponding array position. The returned promise will reject when any task throws or returns a rejection.

when/pipeline

var pipeline, resultsPromise;

pipeline = require('when/pipeline');

resultsPromise = pipeline(arrayOfTasks, arg1, arg2 /*, ... */);

Run an array of tasks in sequence, without overlap, similarly to when/sequence. The first task (e.g. arrayOfTasks[0]) will be called with the arguments passed to when.pipeline(), and each subsequence task will be called with the result of the previous task.

Again, each may return a promise or a value. When a task returns a promise, the fully resolved value will be passed to the next task.

When all tasks have completed, the returned promise will resolve to the result of the last task. The returned promise will reject when any task throws or returns a rejection.

when/parallel

var parallel, resultsPromise;

parallel = require('when/parallel');

resultsPromise = parallel(arrayOfTasks, arg1, arg2 /*, ... */);

Run an array of tasks in "parallel". The tasks are allowed to execute in any order, and may interleave if they are asynchronous. Each task will be called with the arguments passed to when.parallel(), and each may return a promise or a value.

When all tasks have completed, the returned promise will resolve to an array containing the result of each task at the corresponding array position. The returned promise will reject when any task throws or returns a rejection.

Helpers

when/apply

function functionThatAcceptsMultipleArgs(arg1, arg2, arg3) {
    console.log(arg1, arg2, arg3);
}

var functionThatAcceptsAnArray = apply(functionThatAcceptsMultipleArgs);

// Logs 1, 2, 3
functionThatAcceptsAnArray([1, 2, 3]);

Helper that allows using callbacks that take multiple args, instead of an array, with when.all/some/map:

when.all(arrayOfPromisesOrValues, apply(functionThatAcceptsMultipleArgs));

More when/apply examples on the wiki.

Configuration

Paranoid mode

By default, the when module, and all when.js promises are frozen (in enviroments that provide Object.freeze()). This prevents promise consumers from interfering with one another (for example, by replacing a promise's .then() method to intercept results), or from modifying when(), when.defer(), or any other method. It means that when you write code that depends on when.js, you get what you expect.

However, you may not need that level of paranoia. For example, you may trust all the code in your application, either because you or your team members wrote it all, or it comes from other trustworthy sources.

Turning off Paranoid mode

IMPORTANT: This is a tradeoff of safety vs. performance. Please choose carefully for your particular situation! This setting is checked once at load time, and never again. So, once paranoid mode is enabled (default), or disabled, it cannot be changed at runtime.

Due to a major performance degredation of frozen objects in v8, you can turn off when.js's default paranoid setting, and get a significant speed boost. In some tests, we've seen as much as a 4x increase just by not calling Object.freeze.

Use one of the following to turn off paranoid mode, so that when.js no longer calls Object.freeze on any of its internal data structures.

AMD

Use a module configuration to turn off paranoid mode. Your AMD loader configuration syntax may vary. Here are examples for curl.js and RequireJS:

curl.js

{
    baseUrl: //...
    packages: [
        { name: 'when', location: 'path/to/when', main: 'when',
            config: {
                paranoid: false
            }
        }
    ]
}

RequireJS

{
    baseUrl: //...
    config: {
        when: {
            paranoid: false
        },
        // Other module configs ...
    }
}

See the module config section of the RequireJS docs for more info and examples.

Node and RingoJS

Set the WHEN_PARANOID environment variable to "false". For example, depending on your shell:

export WHEN_PARANOID=false

NOTE: It must be the string literal "false". No other value (0, "no", etc.) will work.

Script Tag

Before loading when.js Set window.when_config.paranoid to false:

window.when_config = { paranoid: false };
Jump to Line
Something went wrong with that request. Please try again.