This page looks best with JavaScript enabled

Chain Promises in Javascript

 ·   ·  ☕ 3 min read

A chain promises to process data through a promise-laden gold field.

A simple promise -

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
let promiseToLog = new Promise(function(resolve, reject) {
  console.log("started");
  setTimeout(function() {
    resolve("promise fulfilled.. after timeout");
  }, 300);
});
console.log("promise initialized");

promiseToLog.then(function(val) {
  console.log("resolver", val);
});

As you have seen earlier the promise gets initialized and next statement (‘promise initialized’) gets executed without waiting to resolve promise.

What if you want to execute something after the promise is resolved? This is where promise chaining comes in.

You can chain the then statements to tie multiple executions to a single promise.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
let promiseToLog = new Promise(function(resolve, reject) {
  console.log("started");
  setTimeout(function() {
    resolve(1);
  }, 300);
});
console.log("promise initialized");

let res = 2;
promiseToLog
  .then(function(val) {
    console.log(`promise ${val++}: `, (res *= 2));
    return val;
  })
  .then(function(val) {
    console.log(`promise ${val++}: `, (res *= 2));
    return val;
  })
  .then(function(val) {
    console.log(`promise ${val++}: `, (res *= 2));
  });

/* output
started
promise initialized
promise 1:  4
promise 2:  8
promise 3:  16
*/

The first resolver will receive argument when resolved, show result and return a value. The subsequent then will again be an implicit promise, execution waits until the end is complete to get to the next then. This continues until all thens execute one after the other - each time taking arguments from the previous return.

Practically this has big applications.

  • Wait for response from a third party site, then initiate logic to process the response
  • Pass messages across different systems sequentially (but keeping each one of those async to our own program)
  • Load scripts sequentially on a web page and do a clean dependency management

I am aware that the first two examples are the same - I breathe integration.

Each of the then can have their own promises, but you would have to handle them separately. And, good luck to those who maintain them.

Use a catch statement like normal to process errors for a promise. You can use multiple catch to catch errors from then but you would have to explicitly throw error if you want to stop execution.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
let promiseToLog = new Promise(function(resolve, reject) {
  console.log("started");
  setTimeout(function() {
    resolve(1);
  }, 300);
});
console.log("promise initialized");

let res = 2;
promiseToLog
  .then(function(val) {
    console.log(`promise ${val++}: `, (res *= 2));
    throw "deliberate error";
    // return val;
  })
  .catch(function(err) {
    console.log(`error 1: `, err);
  })
  .then(function(val) {
    console.log(`promise ${val++}: `, (res *= 2));
    return val;
  })
  .catch(function(err) {
    console.log(`error 2: `, err);
  })
  .then(function(val) {
    console.log(`promise ${val++}: `, (res *= 2));
  });

/* output
started
promise initialized
promise 1:  4
error 1:  deliberate error

// no one sent val to next then, so NaN
promise NaN:  8 

promise NaN:  16
*/

As an important aside, it is always a good idea to manage errors within promises without throwing exceptions at the caller. ‘Fail gracefully rather than making a big mess’ is the motto.

Stay in touch!
Share on

Prashanth Krishnamurthy
WRITTEN BY
Prashanth Krishnamurthy
Technologist | Creator of Things