Skip to content
Fetching contributors…
Cannot retrieve contributors at this time
316 lines (209 sloc) 10.7 KB

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.

Update the url in your .git/config, and also .gitmodules for submodules:


Helpful link for updating submodules: Git Submodules: Adding, Using, Removing, Updating

Build Status

A lightweight CommonJS 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.

It's just over 1k when compiled with Google Closure (w/advanced optimizations) and gzipped.

when.js was derived from the async core of wire.js.

What's New?


  • 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.reject(promiseOrValue) that returns a new, rejected promise.
  • promise.always(callback) as a shortcut for promise.then(callback, callback)
  • Highly experimental when/debug module: a drop-in replacement for the main when module that enables debug logging for promises created or consumed by when.js


  • Travis CI integration
  • Fix for cancelable deferred not invoking progress callbacks. (#24 Thanks @scothis)
  • The promise returned by when.chain now rejects when the input promise rejects.


  • Fix for specific situation where null could incorrectly be used as a promise resolution value (#23)


  • Updated README for running unit tests in both Node and Browsers. See Running the Unit Tests below.
  • Set package name to 'when' in package.json


  • Fix for rejections propagating in some cases when they shouldn't have been (#19)
  • Using buster.js for unit tests now.


  • First official when.js release as a part of cujojs.
  • Added when/cancelable decorator for creating cancelable deferreds
  • Added when/delay and when/timeout helpers for creating delayed promises and promises that timeout and reject if not resolved first.

Full Changelog

Quick Start


  1. git clone or git submodule add
  2. Configure your loader with a package:

    packages: [
        { name: 'when', location: 'path/to/when/', main: 'when' },
        // ... other packages ...
  3. define(['when', ...], function(when, ...) { ... }); or require(['when', ...], function(when, ...) { ... });

Script Tag

  1. git clone or git submodule add
  2. <script src="path/to/when/when.js"></script>
  3. when will be available as window.when


  1. npm install git:// (NOTE: npm seems to require a url that starts with "git" rather than http or https)
  2. var when = require('when');


  1. ringo-admin install cujojs/when
  2. var when = require('when');

Docs & Examples

See the API section below, and the wiki for more detailed docs and examples



Register a handler for a promise or immediate value:

when(promiseOrValue, callback, errback, progressback)

// Always returns a promise, so can be chained:

when(promiseOrValue, callback, errback, progressback).then(anotherCallback, anotherErrback, anotherProgressback)


Create a new Deferred containing separate promise and resolver parts:

var deferred = when.defer();

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

The promise API:

// var promise = deferred.promise;

// Main promise API
promise.then(callback, errback, progressback);

// Extended promise API

// Register an alwaysback that will be called when the promise resolves or rejects
promise.always(alwaysback [, progressback]);

The resolver API:

// var resolver = deferred.resolver;

The deferred has the full promise + resolver API:

deferred.then(callback, errback, progressback);


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.

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


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(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(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(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(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., mapFunc)

Traditional map function, similar to, 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:



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


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)


  • 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


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:

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

See the wiki for more info and examples.

Running the Unit Tests

Install buster.js

npm install -g buster

Run unit tests in Node:

  1. buster test -e node

Run unit tests in Browsers (and Node):

  1. buster server - this will print a url
  2. Point browsers at /capture, e.g. localhost:1111/capture
  3. buster test or buster test -e browser


Much of this code was inspired by @unscriptable's tiny promises, the async innards of wire.js, and some gists here, here, here, and here

Some of the code has been influenced by the great work in Q, Dojo's Deferred, and uber.js.

Something went wrong with that request. Please try again.