How to make a synchronous delay inside a for loop?

自古美人都是妖i 提交于 2021-02-17 05:49:27

问题


I'm writing a NodeJS script that calls a bunch of APIs via GET (using request from npm) and saves the responses in a JSON file. I'm using a for to loop through IDs to pass to the APIs, but I'm having trouble putting in a delay between call bursts so I don't spam the API server and make it mad at me (rate limiting). Does anyone know how to do this?

My current code (without any delay):

var fs       = require('fs');
var request  = require('request');

// run through the IDs
for(var i = 1; i <= 4; i++)
{
    (function(i)
    {
        callAPIs(i); // call our APIs
    })(i);
}

function callAPIs(id)
{
    // call some APIs and store the responses asynchronously, for example:
    request.get("https://example.com/api/?id=" + id, (err, response, body) =>
        {
            if (err)
                {throw err;}

            fs.writeFile("./result/" + id + '/' + id + '_example.json', body, function (err)
            {
                if (err)
                    {throw err;}
            });
        });
}

I'm looking for this behavior:

callAPIs(1); // start a burst of calls for ID# 1

// wait a bit...

callAPIs(2); // start a burst of calls for ID# 2

// wait a bit...

// etc

回答1:


You can use the new ES6's async/await

(async () => {
    for(var i = 1; i <= 4; i++)
    {
        console.log(`Calling API(${i})`)
        await callAPIs(i);
        console.log(`Done API(${i})`)
    }
})();

function callAPIs(id)
{
    return new Promise(resolve => {
        // Simulating your network request delay
        setTimeout(() => {
            // Do your network success handler function or other stuff
            return resolve(1)
        }, 2 * 1000)
    });
}

A working demo: https://runkit.com/5d054715c94464001a79259a/5d0547154028940013de9e3c




回答2:


In nodeJS you don't do pauses, you use it's asynchronous nature to await the result of preceding tasks, before resuming on next task.

function callAPIs(id) {
  return new Promise((resolve, reject) => {
  // call some APIs and store the responses asynchronously, for example:
    request.get("https://example.com/api/?id=" + id, (err, response, body) => {
      if (err) {
        reject(err);
      }

      fs.writeFile(`./result/${id}/${id}_example.json`, body, err => {
        if (err) {
          reject(err);
        }

        resolve();
      });
    });
  });
}

for (let i = 1; i <= 4; i++) {
  await callAPIs(array[index], index, array);
}

This code, will do request, write the file, and once it is written to disk, it will process the next file.

Waiting a fixed time before the next task is processed, what if would take a bit more time? What if you're wasting 3 seconds just to be sure it was done...?




回答3:


You might also want to have a look at the async module. It consists of async.times method which will help you achieve the results you need.

var fs = require('fs');
var request = require('request');
var async = require('async');


// run through the IDs
async.times(4, (id, next) => {
    // call some APIs and store the responses asynchronously, for example:
    request.get("https://example.com/api/?id=" + id, (err, response, body) => {
        if (err) {
            next(err, null);
        } else {
            fs.writeFile("./result/" + id + '/' + id + '_example.json', body, function (err) {
                if (err) {
                    next(err, null);
                } else
                    next(null, null);
            });
        }
    });
}, (err) => {
    if (err)
        throw err
});

You can read about it from the below shared url: https://caolan.github.io/async/v3/docs.html#times



来源:https://stackoverflow.com/questions/56613559/how-to-make-a-synchronous-delay-inside-a-for-loop

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!