2

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
Terence Chow
  • 9,287
  • 19
  • 60
  • 120
  • Return another promise that resolves after 1 sec in your "promiseOne then chain, after 2 seconds" callback. Right now your callback returns undefined. and is resolved immediately. – Roland Starke Nov 03 '17 at 10:35
  • that's how promise.all works, and using it for a single promise is redundant anyway – Jaromanda X Nov 03 '17 at 10:49
  • Your answer is here [Using setTimeout in a promise chain](https://stackoverflow.com/questions/39538473/using-settimeout-on-promise-chain/39538518#39538518). – jfriend00 Nov 03 '17 at 16:33

3 Answers3

1

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')
})
James Thorpe
  • 28,613
  • 5
  • 64
  • 82
1

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();
})
Fred Stark
  • 4,802
  • 1
  • 25
  • 37
1

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')
})
Faly
  • 12,529
  • 1
  • 16
  • 34