Examples

A few examples are always helpful to understand how a tool is used. They key to using both the Promise and Deferred classes is performing something in a deferred or asynchronous way. In many practical situations, this involves monitoring DOM element events or receiving notifications from other objects or user actions, but the simplest valid examples - which we will use here - are setTimeout and / or setImmediate, which simply queue up a function to be invoked either after a delay or immediately after the current execution sequence completes.

Create a Method Encapsulating an Asynchronous Operation

As an example, we will create a function that initiates an asynchronous operation (a timeout), returning a Promise to the caller to represent the operation.

1) Create a Deferred to represent the operation
    var d = new Deferred();


2) Configure the operation. Short operations that can be configured and started quickly can be done immediately, while slower operations may be best left to deferred configuration (via a call to setTimeout, for example). Configuration can occur at any time, as can execution: the purpose of both Promise and Deferred is to represent something that happened later. For our example, we simply fulfill the Deferred without a value.
    var d = new Deferred();
    setTimeout(function(){
        d.fulfill();
    }, 10000);


3) Wrap the operation in a function, returning the Promise form of the Deferred. Returning the Promise allows the caller to respond to the fulfillment or rejection of the operation without having access to the underlying Deferred. This keeps the source safe from prying eyes.
    function waitAsync(){
        var d = new Deferred();
        setTimeout(function(){
            d.fulfill();
        }, 10000);
        return d.promise();
    }


4) Parameterize the function for reuse - this is a simple, optional cleanup step.
    function waitAsync(duration){
        var d = new Deferred();
        setTimeout(function(){
            d.fulfill();
        }, duration);
        return d.promise();
    }

Use a Promise

Using our prior method, we can use the returned Promise - specifically its then method - to attach methods to be executed when the Promise is either fulfilled or rejected. Both methods are optional, and only one of the two (if either, since the operation may never complete) will be invoked.

    function waited(){
        alert('I have waited');
    }

    function didntWait(){
        alert('I did not wait');
    }

    waitAsync(10000).then(waited, didntWait);


Because the waitAsync method always succeeds, the waited method will be executed after 10 seconds and we will see the "I have waited" method in an alert window.

Attach Multiple Handlers to a Promise

Given a single Promise, we can attach more than one handler / callback to it by invoking the then method more than once. When the Promise is either completed or rejected, all the appropriate methods will be invoked (i.e. all the fulfilled handlers or all the rejected handlers).

    function waited(){
        alert('I have waited');
    }

    function waitedMore(){
        alert('I have waited more');
    }

    function didntWait(){
        alert('I did not wait');
    }

    function didntWaitMore(){
        alert('I did not wait more');
    }

    var w = waitAsync(10000);
    w.then(waited, didntWait);
    w.then(waitedMore);


The result of this sequence will be the display of two alerts: "I have waited", followed by "I have waited more". While the execution of the callbacks is deferred, they occur in the sequence in which they are attached.

Chain Callbacks

Per the specification, the return value of each invocation of the then method is a new Promise that is fulfilled or rejected after one of the provided callbacks has been invoked. The documentation provides a lot more information regarding return values, but the way to think of the returned Promise is as a continuation of the prior Promise that is executed after the antecedent.

Unlike the previous example, we can ensure that the second alert is queued only after the first has been fulfilled. The difference is subtle, but a continuation provides much better logical flow and management when asynchronous steps are required. The difference is that multiple handlers on a single Promise create parallel execution paths, while continuations provide sequencing.

    function waited(){
        alert('I have waited');
    }

    function waitedMore(){
        alert('I have waited more');
    }

    function didntWait(){
        alert('I did not wait');
    }

    function didntWaitMore(){
        alert('I did not wait more');
    }

    var w = waitAsync(10000);
    w.then(waited, didntWait)
       .then(waitedMore);


As described, first the "I have waited" alert will be shown, then the "I have waited more" alert. Although the result is the same, continuations provide many more control options, including exception propagation, changing fulfillment / rejection status, and ordering long-running or other asynchronous operations.

Last edited Sep 19, 2013 at 7:49 AM by CommanderQ, version 4