On ES6 Promises - Running parallely vs sequentially

If you’re new to JavaScript promises then go through this article JavaScript Promises: an Introduction first.

ES6 Promise basics (optional)

A promise is declared as

const taskPromise = new Promise((resolve, reject) => {
	// Do asynchronous task (aka executor)
	
	// if(success) resolve()
	// else reject()
});

As soon as you declare a Promise, the executor is executed before the Promise constructor even returns the created object. For example: Try it yourself

function getPromise() {
  const taskPromise = new Promise((resolve, reject) => {
    console.log("task started.");
    
    setTimeout(() => {
      console.log("done after 100ms.");
      resolve();
    }, 100);
  });
  
  return taskPromise;
}

getPromise();
Output:
task started.
=> Promise { <pending> }
done after 100ms.

If you want to defer execution of a promise, then you can encapsulate a promise declaration in an anonymous function. Try it yourself

const taskPromise = () => getPromise();
// Now when taskPromise function is invoked, executor will be executed

console.log("**Some other work before promise**");

// Now when taskPromise function is invoked, executor will be executed
taskPromise();
Output:
**Some other work before promise**
task started.
=> Promise { <pending> }
done after 100ms.

Promise.resolve(value): It promisifies the given value.

Understanding “We have a problem with promises” with examples

There is a great article on promises by Nolan Lawson (We have a problem with promises) and I highly recommend to read that. Rest of this post is implementing different examples mentioned in that article.

promiseA().then(function() {
	// How you define this function alters the execution behavior
});

Running promises parallely

Let’s say we have set of tasks with name and time required to finish them. Try it yourself

 const tasks = [
  { name: 'task-1', time: 200 },
  { name: 'task-2', time: 400},
  { name: 'task-3', time: 100},
  { name: 'task-4', time: 50}
];

function getPromise(task) {
  const taskPromise = new Promise((resolve, reject) => {
    console.log(task.name + " started.");
    
    setTimeout(() => {
      console.log(task.name + " done in ", task.time, "ms.");
      resolve(task.name);
    }, task.time);
  });
  
  return taskPromise;
}

getPromise(tasks[0]).then(getPromise(tasks[1]));
Output:
task-1 started.
task-2 started.
=> Promise { <pending> }
task-1 done in  200 ms.
task-2 done in  400 ms.

Even though we chained promises, all promises will be executed parallely. It’s because the promise’s executor block will execute as soon as it’s compiled.

Running promises in order

We’d need to use arrow functions to encapsulate executor block in order to run all promises sequentially. Try it yourself

getPromise(tasks[0]).then(() => getPromise(tasks[1]));
Output:
task-1 started.
=> Promise { <pending> }
task-1 done in  200 ms.
task-2 started.
task-2 done in  400 ms.

Running n promises parallely

Let’s say we don’t know how many tasks we have upfront. How we can chain all promises to start parallely?
We can use reduce function to chain promises and use Promise.resolve() to start. Try it yourself

function executeTasks(tasks) {
  return tasks.reduce((accumulator, task) => {
    return accumulator.then(getPromise(task));
  }, Promise.resolve());
}

executeTasks(tasks);
Output:
task-1 started.
task-2 started.
task-3 started.
task-4 started.
task-3 done in  10 ms.
=> Promise { <pending> }
task-1 done in  200 ms.
task-2 done in  400 ms.
task-4 done in  600 ms.

Running n promises in order

As we did earlier, we need to create anonymous function to start promises. Try it yourself

function executeTasks(tasks) {
  return tasks.reduce((accumulator, task) => {
    return accumulator.then(() => getPromise(task));
  }, Promise.resolve());
}

executeTasks(tasks);
Output:
task-1 started.
task-1 done in  200 ms.
task-2 started.
task-2 done in  400 ms.
task-3 started.
task-3 done in  10 ms.
task-4 started.
task-4 done in  600 ms.