Terence Chow
Terence Chow

Reputation: 11153

Is there a way to guarantee `Promise.all` resolves after the `then` chain of an inner promise?

Is there a way to guarantee Promise.all resolves after the then chain of an inner promise?

Example:

const promiseOne = new Promise((resolve, reject) => {
  setTimeout(function(){
    console.log('promiseOne after 1 second')
    resolve()
  }, 1000)
}).then(()=> {
  setTimeout(function(){
    console.log('promiseOne then chain, after 2 seconds')
  }, 1000)
})


Promise.all([promiseOne])
.then(() => {
  console.log('Promise.all then chain after 1 second')
})

Logs:

promiseOne after 1 second
Promise.all then chain after 1 second
promiseOne then chain, after 2 seconds

Upvotes: 2

Views: 76

Answers (3)

coagmano
coagmano

Reputation: 5671

The easiest way is to pass the promise returned by the last then, which you are already doing. If you take your console log in the first then out of the setTimeout you'll see that it is executing in the order you want.

The reason it's logging in that order is because setTimeout is asynchronous.

Try like so:

const promiseOne = new Promise((resolve, reject) => {
  setTimeout(function(){
    console.log('promiseOne after 1 second')
    resolve()
  }, 1000)
}).then(()=> new Promise(resolve => {
  setTimeout(function(){
    console.log('promiseOne then chain, after 2 seconds')
    resolve()
  }, 1000)
})

By having the first then return a promise, it will wait till after your setTimeout and continue in the correct order.

EDIT: As a bonus, when using setTimeouts, this helper is super useful:

const wait = ms => () => new Promise(resolve => setTimeout(resolve,ms));

Which you can use like so:

Promise.resolve()
.then(wait(2000))
.then(() => {
  doSomething();
})

Upvotes: 1

Faly
Faly

Reputation: 13356

You have to return a new promise in the then chain of the inner promise:

const promiseOne = new Promise((resolve, reject) => {
  setTimeout(function(){
    console.log('promiseOne after 1 second')
    resolve();
  }, 1000)
}).then(()=> {
  return new Promise((resolve, reject) => {
    setTimeout(function(){
      console.log('promiseOne then chain, after 2 seconds');
      resolve();
    }, 1000)  
  });
})

Promise.all([promiseOne])
.then(() => {
  console.log('Promise.all then chain after 1 second')
})

Upvotes: 1

James Thorpe
James Thorpe

Reputation: 32212

The thens are running in the correct order, but the first one is simply setting a timeout, so the console.logs run in the opposite order to the thens. If you want to wait for that timeout to run before continuing the chain, you need to use an additional promise returned from that then:

const promiseOne = new Promise((resolve, reject) => {
  setTimeout(function(){
    console.log('promiseOne after 1 second')
    resolve()
  }, 1000)
}).then(() => new Promise((resolve, reject) => {
  setTimeout(function(){
    console.log('promiseOne then chain, after 2 seconds')
    resolve()
  }, 1000)
  })
)


Promise.all([promiseOne])
.then(() => {
  console.log('Promise.all then chain after 1 second')
})

Upvotes: 1

Related Questions