0

I'm trying to make a loop fetching some info in an API, first I need this loop for to wait for the request to finish and after continue for the next array value, after the loop finish, then I need it to call that function again every 5 seconds, but only after the previous call ends.

Something like this:

let ids = [1, 2];

async function getInfoAPI(ids) {

   for (const id of ids){
      const apiInfo = await fetch(`https://apiurl/${id}`);
      const infoJSON = await apiInfo.json();

      //Do more things here
   }
}

Now I need to call the function and wait for the loop to finish. After the loop is completed then wait for 5 seconds and call the getInfoFromAPI function again. I tried setInterval but if the loop, for some reason, takes more than 5 seconds to respond, the getInfoFromAPI will be called again even if it didn't finish the previous loop.

setInterval(function(){ 
        getInfoAPI(ids);
}, 5000);

Is there any way I could do that using promises or something like that?

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Binho
  • 23
  • 6
  • 1
    Does this answer your question? [Using async/await with a forEach loop](https://stackoverflow.com/questions/37576685/using-async-await-with-a-foreach-loop) – evolutionxbox Jun 06 '22 at 00:33
  • Thank @evolutionxbox but that doesn't answer my question. I still need the function to be called again 5 seconds after all process is done. – Binho Jun 06 '22 at 00:37

4 Answers4

3

You can do something like this:

function run() {
    getInfo(...).then(() => {
        setTimeout(run, 5000)
    });
}

run().catch(err => {
   console.log(err);
});

Or, I prefer using a promise version of setTimeout(). I the latest version of nodejs, you can use timersPromises.setTimeout() and it returns a promise:

import { setTimeout } from 'timers/promises';

async function run() {
    await getInfo(...)
    await setTimeout(5000);
    return run();
}

run().catch(err => {
   console.log(err);
});

Or, use a while loop with await:

import { setTimeout } from 'timers/promises';

async function run() {
    while (true) {
        await getInfo(...)
        await setTimeout(5000);
    }
}

run().catch(err => {
   console.log(err);
});
jfriend00
  • 683,504
  • 96
  • 985
  • 979
1

You can achieve this by importing the promise based setTimeout that ships with NodeJs 16+ and using it as follows:

Import:

import { setTimeout } from "timers/promises"

Use:

while (true) {
  await getInfoAPI(ids);
  await setTimeout(5000);
}
Ovidijus Parsiunas
  • 2,512
  • 2
  • 8
  • 18
  • The regular `setTimeout()` does not return a promise so `await` won't do anything with it as it returns a `timerID`. There is a different `setTimeout()` that does return a promise. – jfriend00 Jun 06 '22 at 00:50
  • @Binho has tagged this with ```node.js```, and ```setTimeout``` does return a promise when run in that environment. – Ovidijus Parsiunas Jun 06 '22 at 00:51
  • No, it does not return a promise in nodejs. Nodejs doc [here](https://nodejs.org/api/timers.html#settimeoutcallback-delay-args). It returns a `timerID`. Your answer could illustrate how to use [timersPromises.setTimeout()](https://nodejs.org/api/timers.html#timerspromisessettimeoutdelay-value-options) instead which is a different version that does support promises. – jfriend00 Jun 06 '22 at 00:52
  • Sorry, I meant the use of the ```import { setTimeout } from "timers/promises"```, which does ship with nodejs 16+ https://nodejs.org/api/timers.html#timers-promises-api, I'll update my answer to be more specific – Ovidijus Parsiunas Jun 06 '22 at 01:02
1

Use recursion:

async function getInfoPeriodically() {
  await getInfoAPI(ids);
  setTimeout(() => {
    getInfoPeriodically()
  }, 5000);
}

You can add the parameters to customize this function/pass values in but this is the idea.

Son Nguyen
  • 1,472
  • 8
  • 16
0

Why don't you try to use Promise.all or Promise.allSettled? With that you can use concurrency to fetch all the data at once, instead that one by one. In case you need to do it one by one, I suggest you to use for-await...of.

Anthony Luzquiños
  • 739
  • 11
  • 23