JavaScript Promise Cheat-Sheet

Promise is a new JavaScript feature standardized in ES6, although it has been implemented by various libraries for a while now. It is a way to manage asynchronous code, letting you easily translate nested callbacks into a 'do foo. Then do bar, followed by baz and then boobliboo'. You can achieve the same effect with or without Promises, but Promises make it much simpler.

When learning about any JavaScript features, my go-to place to start is MDN. For Promises, I also found a number of other great articles which I used in compiling this cheat-sheet. Here are the ones I would suggest as recommended reading:

How to: Create a Promise

Using the constructor

/* Creating a Promise using the constructor */

var p = new Promise(function(resolve, reject) {
  fetchDataFromServer(function(error, data) {
    if (error)
      reject(error);
    else
      resolve(data);
  });
});

Using Promise.protype.then or Promise.protype.catch

Promise.protype.then and Promise.protype.catch both accept a function (say f1) and return another Promise (say p1). The function may return a value (say v)or a Promise (say p2). p1 will then resolve with v (if v was returned by f1) or the resolution of p2 (if p2 was returned by f1).

/* Creating a Promise using Promise.prototype.then */

var firstPromise = new Promise(...);
var secondPromise = p.then(function(data){
  return 5;
});

secondPromise.then(function(x){
  console.log(x); //x is 5
});

//OR,
var firstPromise = new Promise(...);
var secondPromise = p.then(function(data){
  return new Promise(function(resolve, reject){
    resolve(10);
  });
});

secondPromise.then(function(x){
  console.log(x); //x is 10
});

Using Promise.resolve

Promise.resolve accepts a Promise or an object and will resolve with the resolution of the Promise or the supplied object.

/* Creating a Promise using Promise.resolve */

// A value supplied to Promise.resolve
var p1 = Promise.resolve(5);
p1.then(function(x){
  console.log(x); // prints 5 on console
});

// A promise supplied to Promise.resolve
var p2 = new Promise(function(resolve, reject) {
  resolve(10);
});
var p3 = Promise.resolve(p2);
p3.then(function(x){
  console.log(x); // prints 10 on the console
})

How to: Execute promises in sequence

Chaining is what makes Promises so useful and lets you execute tasks in sequence. A Promise object (say P1) has two instance methods, 'then' and 'catch'. Both of these expect a function (say f1) and return a new Promise (say P2). If the function f1 returned a value v, then P2 resolves in v. And of f1 returned a Promise (say P1.5) then P2 resolves with the resolution value of P1.5 (we also saw this in the previous section, creating Promises).

var p1 = new Promise(function(resolve, reject) {
  someAsyncOperation(function(err, data){
    if (err)
      reject(err);
    else
      resolve(data);
  });
});

p2 = p1.then(function(arg) {
  return 5;
})

p2.then(function(x) {
  console.log(x); // prints 5
})

//OR,

p2 = p1.then(function() {
  return new Promise(function(resolve, reject) {
    resolve(10);
  });
})

p2.then(function(x){
  console.log(x); // prints 10
});

How to: Execute the same operation on a number of items in sequence (or Array.map asynchronously using Promises)

There are a few well established libraries that let you execute asynchronous operations on a collection; Or as I like to say, enable asynchronous Array.map. For instance, the well known Q and async.js. Incidentally, the readme for Q has an excellent explanation of Promises.

If you wanted to roll your own solution, you must understand that a Promise is executed as soon as you create it. It may resolve at some later point, but it will start executing. Keeping this in mind, we conclude that we must create the Promise as we want to execute it.

var data = ['a', 'b', 'c', 'd'];

//operation is a function that accepts dataArr[i] and returns a Promise
function executeInSequence(dataArr, operation) {
  return new Promise(function(resolveFinal, rejectFinal) {
    var index = 0;
    var result = [];
    var tick = function() {
      console.debug('tick: ', index);
      if (index < dataArr.length)
        operation(dataArr[index++]).then(handleTick, rejectFinal);
      else
        resolveFinal(result);
    }

    var handleTick = function(opResultForI) {
      console.debug('handleTick: ', opResultForI);
      result.push(opResultForI);
      tick();
    }

    console.debug('Start executing');
    tick();
  });
}

var p = executeInSequence(data, function(d){
  console.debug('Opration(', d, ')');
  return new Promise(function(resolve, reject) {
    console.debug('Waiting on ', d);
    window.setTimeout(function(){
      resolve(d + ' // resolved at ' + Date.now());
    }, 1000);
  });
});

p.then(function(result){
  console.debug(result);
}).catch(function(err) {
  console.error(err);
});

How to: Promise exception handling

By supplying the error handler as the second argument to Promise.prototype.then

Promise.prototype.then actually has a second, optional argument which is also expected to be a function. This function is called when the Promise is rejected. A promise can be reject explicitly by calling the reject function, or implicitly by causing an exception to be thrown.

var p1 = new Promise(function(resolve, reject) {
  reject(new Error('I am rejecting this Promise'));
});

p1.then(function(){
  console.log('This function is never called');
}, function(err) {
  console.error(err); // prints the error on the console
});

// ALSO, implicitly rejecting
var p1 = new Promise(function(resolve, reject){
  resolve(boo.boo);  // create a ref error
});
var z = p1.then(function(y){
  console.log('This function still wont be called');
}, function(err){
  console.error(err); // Prints ReferenceError: boo is not defined(…)
});

By calling Promise.prototype.catch

This has the advantage that you can attach it at the end of your Promise chain and it will receive any error caused anywhere within the Promise chain.

new Promise(function(resolve, reject){
  reject(new Error('Reject this Promise for Science'));
})   //Notice NO semicolon here
.catch(function(err){
  console.log(err);  //Prints error
});

//OR
new Promise(function(resolve, reject){
  resolve(5);
})
.then(function(){
  throw new Error('Monkey error encountered.');
})
.catch(function(err){
  console.log(err);  //Prints error
});

How to: Batch several Promises together

Using Promise.all

Promise.all accepts an array containing Promises (or objects, or a mix of the two) and returns another Promise. Once all the promises in the array are resolved this new Promise resolves with an array containing the resolution value of the Promises.

var promiseArr = [Promise.resolve(5), Promise.resolve(10), Promise.resolve(15), 8, 2, 'a string'];

Promise.all(function(values){
  console.log(values); //Prints [5, 10, 15, 8, 2, 'a string']
});

Using Promise.race

If you only want the first resolution value out of a bunch of promises, then Promise.race has got you covered

var p1 = new Promise(function(resolve, reject) {
  //Resolve after 1000ms
  setTimeout(function() {
    resolve(1000);
  }, 1000);
});

var p2 = new Promise(function(resolve, reject) {
  //Resolve after 10ms
  setTimeout(function() {
    resolve(10);
  }, 10);
});

var p3 = new Promise(function(resolve, reject) {
  //Resolve after 2000ms
  setTimeout(function() {
    resolve(2000);
  }, 2000);
});

Promise.race([p1, p2, p3])
  .then(function(x) {
    console.log(x); //Prints 10
  });