像异步中的瀑布一样执行forEach

Sam*_*duc 7 javascript asynchronous google-api node.js

我正在尝试通过Node.js脚本从Google API的地址列表中检索经度和纬度.呼叫本身工作正常,但因为我有大约100个地址要提交.我async.forEach在一个数组上使用了一个,但是调用太快了,我收到错误"你已经超过了这个API的速率限制."

我发现每24小时呼叫次数限制为2500次,每秒最多10次.虽然我每天可以使用2500个,但是我的通话速度太快了.

我现在必须编写一个函数来延迟调用,以免达到极限.以下是我的代码示例:

async.forEach(final_json, function(item, callback) {
    var path = '/maps/api/geocode/json?address='+encodeURIComponent(item.main_address)+'&sensor=false';
    console.log(path);
    var options = {
      host: 'maps.googleapis.com',
      port: 80,
      path: path,
      method: 'GET',
      headers: {
        'Content-Type': 'application/json'
      }
    }
    // a function I have who makes the http GET
    rest.getJSON(options, function(statusCode, res) {
      console.log(res);
      callback();
    });
}, function() {
  // do something once all the calls have been made
});
Run Code Online (Sandbox Code Playgroud)

你会如何实现这一目标?我尝试将我的rest.getJSON内部设置为100毫秒,setTimeoutforEach迭代遍历所有行的速度非常快,以至于它setTimeout几乎同时启动,因此它不会改变任何东西......

async.waterfall像它看起来会做的伎俩,但事情是我不知道我到底有多少行都会有,所以我不能硬编码的所有函数调用.说实话,这会让我的代码变得非常丑陋

Mik*_*rds 3

这个想法是,您可以创建一个与or函数rateLimited非常相似的函数,除了任何不立即执行的调用都会排队并在速率限制时间段到期时按顺序运行。throttleddebounced

基本上,它创建并行的 1 秒间隔,通过计时器重新调度进行自我管理,但最多只perSecondLimit允许间隔。

function rateLimit(perSecondLimit, fn) {
    var callsInLastSecond = 0;
    var queue = [];
    return function limited() {
        if(callsInLastSecond >= perSecondLimit) {
            queue.push([this,arguments]);
            return;
        }

        callsInLastSecond++;
        setTimeout(function() {
            callsInLastSecond--;
            var parms;
            if(parms = queue.shift()) {
                limited.apply(parms[0], parms[1]);
            }
        }, 1010);

        fn.apply(this, arguments);
    };
}
Run Code Online (Sandbox Code Playgroud)

用法:

function thisFunctionWillBeCalledTooFast() {}
var limitedVersion = rateLimit(10, thisFunctionWillBeCalledTooFast);

// 10 calls will be launched immediately, then as the timer expires
// for each of those calls a new call will be launched in it's place.
for(var i = 0; i < 100; i++) {
    limitedVersion();
}
Run Code Online (Sandbox Code Playgroud)