After having read the absolutely wonderful exploring ES6, I wanted to use my newly acquired ES6 skills in a new project. And promises were always the crown jewel of esoteric topics to me (after monads of course :P).

Finally a new project came along, and I excitedly sat down to apply all my knowledge into practice. I started nice and easy, moved on to Promise.all() to load multiple promises in parallel, but then a use case cropped up, where I had to load promises in series. No sweat, just head over to SO, and look up the answer. Surely, I am not the only one here with this requirement. Sadly, most of the answers pointed to using async and other similar libraries. Nevertheless, I did get an answer which just used plain ES6 code to do that. Aww yiss ! Problemo solved.

I couldn’t declare the functions in an array like the example. Because I had a single function. I modified the code a bit to adjust for my usecase. This was how it came out -

'use strict';
const load = require('request');

let myAsyncFuncs = [
  computeFn(1),
  computeFn(2),
  computeFn(3)
];

function computeFn(val) {
  return new Promise((resolve, reject) => {
    console.log(val);
    // I have used load() but this can be any async call
    load('http://exploringjs.com/es6/ch_promises.html', (err, resp, body) => {
      if (err) {
        return reject(err);
      }
      console.log("resolved")
      resolve(val);
    });
  });
}

myAsyncFuncs.reduce((prev, curr) => {
  console.log("returned one promise");
  return prev.then(curr);
}, Promise.resolve(0))
.then((result) => {
  console.log("At the end of everything");
})
.catch(err => {
  console.error(err);
});

Not so fast. As you can guess, it didn’t work out. This was the output I got -

1
2
3
returned one promise
returned one promise
returned one promise
At the end of everything
resolved
resolved
resolved

The promises were all getting pre-executed and didn’t wait for the previous promise to finish. What is going on ? After some more time, got this (Advanced mistake #3: promises vs promise factories).

Aha ! So the promise will start to execute immediately on instantiation. And will resolve only when called. So all I had to do was delay the execution of the promise until the previous promise was finished. bind to the rescue !

'use strict';
const load = require('request');

let myAsyncFuncs = [
  computeFn.bind(null, 1),
  computeFn.bind(null, 2),
  computeFn.bind(null, 3)
];

function computeFn(val) {
  return new Promise((resolve, reject) => {
    console.log(val);
    // I have used load() but this can be any async call
    load('http://exploringjs.com/es6/ch_promises.html', (err, resp, body) => {
      if (err) {
        return reject(err);
      }
      console.log("resolved")
      resolve(val);
    });
  });
}

myAsyncFuncs.reduce((prev, curr) => {
  console.log("returned one promise");
  return prev.then(curr);
}, Promise.resolve(0))
.then((result) => {
  console.log("At the end of everything");
})
.catch(err => {
  console.error(err);
});

And now -

returned one promise
returned one promise
returned one promise
1
resolved
2
resolved
3
resolved
At the end of everything

Finally :)

Conclusion - If you want to execute promises in series, dont create promises which start executing. Delay their execution untill the previous promise has finished.


Agniva De Sarker

My journal on Software, Bugs, Tips & Tricks.