Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you synchronously resolve a chain of es6 promises?

Tags:

I have a function from a library that returns a promise. I need to run this function multiple times, but each iteration must wait until the previous task is done.

My assumption was that I could do this:

promiseReturner(1)
  .then(promiseReturner(2)
  .then(promiseReturner(3)
  .then(...)

Which could be simplified using a loop:

var p = Promise.resolve();
for (var i=1; i<=10; i++) {
  p = p.then(promiseReturner(i));
}

However, when I do this each promise in the chain is executed at the same time, instead of one after the other as .then() seems to imply. Clearly I'm missing something fundamental about promises -- but after reading several tutorials and blog posts I'm still lost.

Here's a codepen I wrote up to demonstrate my attempt.

like image 290
Ben Davis Avatar asked Feb 23 '15 20:02

Ben Davis


People also ask

Does promise execute synchronously?

A promise is used to handle the asynchronous result of an operation. JavaScript is designed to not wait for an asynchronous block of code to completely execute before other synchronous parts of the code can run. With Promises, we can defer the execution of a code block until an async request is completed.

How do you chain promises in JavaScript?

JavaScript Promise Chaining Promises are useful when you have to handle more than one asynchronous task, one after another. For that, we use promise chaining. You can perform an operation after a promise is resolved using methods then() , catch() and finally() .

Which method is used to resolve a promise?

resolve() method in JS returns a Promise object that is resolved with a given value. Any of the three things can happened: If the value is a promise then promise is returned. If the value has a “then” attached to the promise, then the returned promise will follow that “then” to till the final state.

Can a promise have multiple resolve?

No. It is not safe to resolve/reject promise multiple times. It is basically a bug, that is hard to catch, becasue it can be not always reproducible.


2 Answers

Your "non-loop" solution shouldn't work either. You have to pass a function to .then, not a promise:

var p = Promise.resolve();
for (var i=1; i<=10; i++) {
  (function(i) {
      p = p.then(function() {
          return promiseReturner(i);
      });
  }(i));
}

If that function returns a promise, then you get that chaining effect.

More info about promises on MDN.


Can be simplified with let (and arrow functions):

var p = Promise.resolve();
for (let i=1; i<=10; i++) {
    p = p.then(() => promiseReturner(i));
}

Or .bind (which is ES5):

var p = Promise.resolve();
for (var i=1; i<=10; i++) {
    p = p.then(promiseReturner.bind(null, i));
}
like image 98
Felix Kling Avatar answered Sep 20 '22 06:09

Felix Kling


If you are using es6, you can achieve this using array.reduce. I think quite neatly.

const functions = [/* array of functions which return promises */];
const finalPromise = functions.reduce(async (promise, asyncFn) => {
  await promise;
  return asyncFn();
}, Promise.resolve());
like image 27
Alastair Brayne Avatar answered Sep 22 '22 06:09

Alastair Brayne