3

I have some nested Node.js forEach loops which are hitting API rate limiters and I would like to slow them down so that they are not hitting the rate limit. I have tried adding a setTimeout on the end of the loop but that has no impact at all on the speed of the requests. Ideally, I would be able to send a request every 2 seconds. How can I achieve this? Everything online seems to talk about rate-limiting an API but nothing on the sending side of things.

3
  • Please show some code of where you're calling the API wihin a loop Commented Jan 26, 2022 at 16:27
  • This question should answer your question: stackoverflow.com/questions/37977602/… Commented Jan 26, 2022 at 16:34
  • @Jamiec I don't think that would be of help too much past linking to what a forEach loop looks like. This is a general question about rate-limiting a forEach loop, not an exact rate limit my API. I have other places in my app that I would like to limit a forEach loop too so no point in a specific solution when I need general for multiple use cases Commented Jan 26, 2022 at 16:35

2 Answers 2

3

To delay in a loop, first of all, your function must be async.

You can then await a promise that resolves after 2 seconds. Such a delay can be inserted as a one-liner like this:

await new Promise(resolve => setTimeout(resolve, 2000));

...or as a handy function like:

const delay = time => new Promise(resolve => setTimeout(resolve, time));

...which can then be used in a loop like:

async function fetchEverything() {
   for (let thing of things) {
      await fetchThing(thing);
      await delay(2000);
   }
}
Sign up to request clarification or add additional context in comments.

1 Comment

If you're seeking guidance with forEach specifically, please see this question
0

You can make a generic extension on Array which can insert a delay in between each iteration, you will want to make the function async so you can await it (and therefore know when it's finished).

Array.prototype.forEachLimited = async function(fn, timeBetweenCallsMs){
    
    const delay = async () => new Promise(resolve => setTimeout(resolve, timeBetweenCallsMs));
    
    for(var i=0;i<this.length;i++){
      fn(this[i]);
      await delay();
    }
};


(async function(){
  var myArr = [1,2,3,4,5];
  await myArr.forEachLimited(i => console.log(i), 2000);
  console.log("Finished");
})();

Some may frown at adding this to the Array.prototype, it will work just as well as a normal function taking the array as an argument, so the same thing without adding it to Array.prototype

async function forEachLimited(arr, fn, timeBetweenCallsMs) {

  const delay = async() => new Promise(resolve => setTimeout(resolve, timeBetweenCallsMs));

  for (var i = 0; i < arr.length; i++) {
    fn(arr[i]);
    await delay();
  }
};


(async function() {
  var myArr = [1, 2, 3, 4, 5];
  await forEachLimited(myArr, i => console.log(i), 2000);
  console.log("Finished");
})();

2 Comments

Downvoter wish to comment?
I would suggest that the downvote has to do with the mutation of the prototype. It's considered poor form by some to touch the prototype because if a function is ever added by the vendor that matches yours, it could cause unpredictable behaviour. Either in your code or in 3rd party libraries that expect that function to behave in specific ways. Probably didn't scroll down to see the non mutation example or still downvoted it on principal.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.