0
function promise1 (num) {
  return new Promise(resolve1 => {
    let timeout = Math.random() * 5000
    setTimeout(() => {
      console.log(num)
      resolve1()
    }, timeout)
  })
}

let promiseVar = promise1(0)
for (let i = 1; i < 5; i++) {
  promiseVar.then(() => {
    promiseVar = promise1(i)
  })
}

I've got a function that creates a promise that might take an arbitrary amount of time to complete but I want the promises executed in a specific order. Inside the for loop I expect it to only begin the next promise after the previous one has resolved but the console logs the numbers in a random order as if it starts each promise before the last one has resolved. Is there a better way to execute a series of promises like this or have I overlooked something.

Auh
  • 145
  • 11
  • I suspect the second one always starts after the first one, but that each subsequent one doesn't wait. Is that right @Auh? – TKoL Feb 11 '19 at 17:49
  • Seems like Ivar posted a link to a good solution. Actuall TKoL it seems that 4 is the number that gets printed second quite consistently. Thanks to Ivar this is no longer an issue for me but I'm still curious about why it behaves this way – Auh Feb 11 '19 at 17:51
  • 1
    You can just make the interior of the loop: `promiseVar = promiseVar.then(() => promise1(i))` which will effectively chain them. – Mark Feb 11 '19 at 17:53
  • @Auh, maybe you did something slightly different. I'll add an answer so you can see the full snippet. – Mark Feb 11 '19 at 17:58

3 Answers3

2

Try something like this:

function promise1 (num) {
  return new Promise(resolve1 => {
    let timeout = Math.random() * 5000
    setTimeout(() => {
      console.log(num)
      resolve1()
    }, timeout)
  })
}

function runNext(i, max) {
  if (i > max) return Promise.resolve(true);
  return promise1(i).then(() => runNext(i+1));
}

runNext(0,4);

Or make it really easy on yourself and use async/await

(async () => {
  for (let i = 0; i < 5; i++) {
    await promise1(i);
  }
})();
TKoL
  • 13,158
  • 3
  • 39
  • 73
1

You can run all promises at the same time (if the order of rejecting/resolving promise doesn't matter) with promise.all. Also there is promise chaining when there is need to be sure that first in order must be resolved.

Konrad
  • 952
  • 10
  • 25
0

You can set promiseVar to the promise that results from then() in the loop. This will have the effect of changing the promises:

function promise1(num) {
  return new Promise(resolve1 => {
    let timeout = Math.random() * 1000
    setTimeout(() => {
      console.log(num)
      resolve1()
    }, timeout)
  })
}

let promiseVar = promise1(0)
for (let i = 1; i < 5; i++) {
  promiseVar = promiseVar.then(() => promise1(i))
}

This will create all the promises, but it will leave the last one without a then. You can use promiseVar.then() outside the loop to know when the last promise has resolved.

Mark
  • 90,562
  • 7
  • 108
  • 148
  • I was originally getting some inconsistent results on node but I think this solution works thanks. Any explanation why reasigning the var inside the `then` was incorrect? I'm struggling to wrap my head around it – Auh Feb 11 '19 at 18:03
  • 1
    Yeah @Auh, that reassignment inside `then()` doesn't happen until the promise resolves, which is long after the entire `for` loop has finished. In the above example, you're reassigning in the loop itself, not the async callback. – Mark Feb 11 '19 at 18:04
  • Of course. It only does the reasignment after the random time has passed. Thanks very much. Silly oversight by me. – Auh Feb 11 '19 at 18:06