2

I am trying to work with an api where I have to send a request for each item in a list. However, I see that the loop doesn't seem to wait for every request, i.e, the loop doesn't work as expected. Here's the code below

getInfo = async () => {
   const mylist = ["item1","item2","item3","item4","item5","item6","item7"]
   const responses = []
   const len = mylist.length
   for (let i = 0; i < len; i++) {
      //console.log("inside loop")
      await axios.get("some_url/"+mylist[i])
          .then(res => {
              responses.push(res.data)
          })
   }

When I run the program, all the console.log("inside loop") executes immediately without waiting for the request to be complete.

How can I modify the code so as to wait for each response to be completed before updating the for loop counter variable?

Dev5
  • 449
  • 3
  • 15
  • You don't need to add `then` section when you use `async await` syntax. You can just put `console.log` after the await statement. `const res = await axios.get()` – Dilshan Sep 20 '20 at 11:16
  • The `.then()` usage is a bit weird (`cons res = await …; responses.push(res.data)` would be more idiomatic), but it should work as expected nonetheless. Is this your actual code? – Bergi Sep 20 '20 at 11:29
  • 1
    Does this answer your question? [How to execute promises sequentially, passing the parameters from an array?](https://stackoverflow.com/questions/43082934/how-to-execute-promises-sequentially-passing-the-parameters-from-an-array) – Marcus Ilgner Sep 20 '20 at 11:43

2 Answers2

3

You could try re-arranging the code to something like this. But using a Promise.all with Array.prototype.map would be more idiomatic solution for the problem.

await the async call (remove unnecessary .then call) and then console.log

getInfo = async () => {
   const mylist = ["item1","item2","item3","item4","item5","item6","item7"]
   const responses = []
   const len = mylist.length
   for (let i = 0; i < len; i++) {
      responses.push((await axios.get("some_url/"+mylist[i])).data)
      console.log("inside loop")
   }
}
Tibebes. M
  • 6,940
  • 5
  • 15
  • 36
3

Internally, await is translated into a Promise chain. Since the for loop can't be transformed into a Promise-continuation, you'll need to convert it to a Promise-based construct.

Depending on what you want to achieve there are multiple ways to go about it. Constructing the responses array could be done with a map statement.

const promises = mylist.map(item => {
   return axios.get("some_url/"+item).then(res => { return res.data; })
});
const data = await Promise.all(promises);

No manual pushing items around or fiddling with the array length.

Marcus Ilgner
  • 6,935
  • 2
  • 30
  • 44
  • 1
    "*Since the for loop can't be transformed into a Promise-continuation*" - of course it can? – Bergi Sep 20 '20 at 11:30
  • 2
    The OP explicitly complains about "*all the `console.log("inside loop")` executes immediately without waiting for the request to be complete*", so no, they do **not** want the concurrent `Promise.all` solution! It should "*wait for each response to be completed before*" going to the next iteration. – Bergi Sep 20 '20 at 11:31