-1

I'm developing an app and I'm having a problem. I want to run two functions inside a forEach loop, which means for each iteration run both functions once.

This is very simple to do when you think about it, but my functions are asynchronous and my first function needs to finish before the second one executes.

Reason why i made these functions async is that in my app these functions represent an API call.

I will show you a quick example in which i used setTimeout() instead of API calls.

async function f(){
  await setTimeout(()=>{
    console.log("FIRST")
  },1000)
}

async function f2(){
  await setTimeout(()=>{
    console.log("SECOND")
  },3000)
}

for(var i = 0;i < 5; i++){
  f() 
  f2()
}

When I run this the output is:

FIRST
FIRST
FIRST
FIRST
FIRST
SECOND
SECOND
SECOND
SECOND
SECOND

And i need my output to be:

FIRST
SECOND
FIRST
SECOND
FIRST
SECOND
FIRST
SECOND
FIRST
SECOND

Any idea how to achieve this? Would be very helpful.

  • They cannot be made to run synchronously, but you *can* make them run in sequence. There is a difference. To execute them in sequence just do `f().then(f2)`. However, that will run them in pairs, if you want them to go `f` -> `f2` -> `f` -> `f2` [you can also do tha](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce#Running_Promises_in_Sequence) – VLAZ Apr 14 '20 at 09:15
  • I tried the reduce method but it didn't work. What happens is that the first function executes 5 times (because I iterated the loop 5 times) and then the second function executes 5 times, which is not the desired result. – Rron Jakupi Apr 14 '20 at 09:41
  • Well, you need to set up the chain properly for two functions. The idea is to chain the following operation: `f().then(f2).f().then(f2).f().then(f2).f().then(f2).f().then(f2)` - it's `f` followed by `f2` 5 times. Since I don't know the real source code, and I assume this is a simplification, I can't really say the best way to `.reduce` these. But you can just do the same with a loop `p = Promise.resolve(); for() { p = p.then(f).then(f2) }` and it will have a similar effect. – VLAZ Apr 14 '20 at 09:45
  • No particulary, the result is still the same. The first function executes 5 times then the second one executes 5 times. – Rron Jakupi Apr 14 '20 at 11:17
  • Then I don't know what to say - this is how you chain promises sequentially. If it doesn't work, then you must not have promises that are resolved properly. – VLAZ Apr 14 '20 at 11:29
  • They are resolving properly, I can assure you that. Can the problem be that both methods are async and are not waiting for one another to finish? – Rron Jakupi Apr 14 '20 at 11:59
  • I'm not convinced. If the `.then` chains don't execute sequentially, then it seems promises resolve prematurely. That's exactly the problem with the sample code you have in the question `await setTimeout()` will *not* wait for the `setTimeout` to execute, so you'd just be queuing all timers at once, and all `f()`s and `f2()`s would *resolve* almost immediately, then fire five delayed function from `f()` a second later, and in two more seconds the delayed functions from `f2()` would fire. Again, I don't know what your real code looks like but based on behaviour you report, it seems similar. – VLAZ Apr 14 '20 at 12:07
  • I used setTimeout in this to mimic a real-life API call so image an API call with fetch instead of setTimeout. When i tried your suggestion in my project it still didn't work, and i got the same result (first function running x times then second one x times). – Rron Jakupi Apr 14 '20 at 12:12
  • Then your real code doesn't correctly handle promises, either. [Here is how it should work if it did](https://jsbin.com/suduhobogi/1/edit?js,console). EDIT changed the link, I had copied the wrong one the first time. – VLAZ Apr 14 '20 at 12:24

1 Answers1

0

Wait for the first async function to finish and then call the second one

for(var i = 0;i < 5; i++){
  f1().then(res => {
   return f2()
  }
}

This will not guarantee your desired output, but will guarantee that a call to f2 was done after a call to f1

Note: you could collect all promises into an array and maybe call Promise.all if you want to know when all of them are finished.

Radu Diță
  • 10,795
  • 1
  • 23
  • 31