JS · PromisesMay 28, 2015 · 2 min read

10 Things I Learned About Promises

Promise chaining only works if your fulfillment handlers actually return promises. Three patterns where that's easy to get wrong, and what happens when you don't.

A list of things that I've learned while using promises...

Promises that immediately resolve

JavaScript
var p = new Promise(function(resolve, reject){
  resolve(42);
});

You can do:

JavaScript
var p = Promise.resolve(42);

Returning Promises

The following does not print out statements one second apart:
JavaScript
Promise.resolve(42).then(function(){
    window.setTimeout(function(){
        console.log(window.performance.now());
    }, 1000);
}).then(function(){
    window.setTimeout(function(){
        console.log(window.performance.now());
    }, 1000);    
});

The fulfillment handler for the first then immediately resolves and returns undefined, which kicks off the fulfillment handler for the second then.

If you want to execute the fulfillment handler for the second then only after the first fulfillment handler has completed, it needs to return a Promise.

JavaScript
Promise.resolve(42).then(function(){
    return new Promise(function(resolve, reject){
        window.setTimeout(function(){
            console.log(window.performance.now());
            resolve();
        }, 1000);
    });
}).then(function(){
    window.setTimeout(function(){
        console.log(window.performance.now());
    }, 1000);    
});

Notice that it's more than just wrapping your code in a new Promise:

JavaScript
return new Promise(function(resolve, reject){...})

You'll need to add a resolve() expression, otherwise it will hang.

Returning the appropriate Promise

This won't work as intended:
JavaScript
function myPromise() {
    var url = 'someURLHere';
    return Promise.resolve(window.setTimeout(function(){console.log('myPromise resolved');}, 2000));
}

myPromise().then(function(output){
    console.log(output);
    console.log('end');
});

This returned promise in myPromise is immediately resolved; the value that is passed on is the result of window.setTimeout, specifically the timeoutID. The fulfillment handler would immediately fire, outputting end, then after two seconds you will get confirmation that myPromise has resolved.

Instead, try this:

JavaScript
function myPromise() {
    var url = 'someURLHere';
    return new Promise(function(resolve) {
        window.setTimeout(function() {
            console.log('myPromise resolved');
            resolve();
        }, 2000)
    });
}

myPromise().then(function(output){
    console.log(output);
    console.log('end');
});