在async中执行forEach,像瀑布一样

我试图通过Node.js脚本从Google API的地址列表中检索经度和纬度。 电话本身工作正常,但由于我有大约100个地址提交。 我在数组上使用了async.forEach ,但是调用速度太快,而且出现错误“您已超出此API的速率限制”。

我发现每24小时呼叫次数限制在2500次,最多10次。 虽然我可以每天2500,但是我限制速度太快了。

我现在必须写一个function,这个function可以延迟电话的数量,使其达到极限。 这是我的代码示例:

 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 }); 

你将如何着手实现这一目标? 我试图把我的rest.getJSON在一个100ms的setTimeoutforEach遍历所有的行如此之快,它几乎在同一时间启动所有的setTimeout ,因此它不会改变任何东西…

async.waterfall看起来好像是可以做的,但是我不知道到底有多less行,所以我不能硬编码所有的函数调用。 说实话,这将使我的代码真的很难看

这个想法是,你可以创build一个rateLimited函数, rateLimited函数非常像一个被throttled或者被debounced函数,除非任何没有立即执行的调用在速度限制时间段到期之后才会排队和运行。

基本上,它会创build并行1秒的时间间隔,通过定时器重新计划自我pipe理,但只允许达到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); }; } 

用法:

 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(); } 

以下是我将如何破解它(注意: arr是你的位置数组):

 function populate(arr, callback, pos) { if(typeof pos == "undefined") pos=0; var path = '/maps/api/geocode/json?address='+encodeURIComponent(arr[pos].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); }); pos++; if(pos<arr.length) setTimeout(function(){ populate(arr,callback,pos); },110); //a little wiggle room since setTimeout isn't exact else callback(); } 

你可以添加一个限速function,但是,恕我直言,它引入了不必要的复杂性。 所有你真正想要做的就是每十分之一秒左右调用一次函数,直到完成你的列表为止。

这当然不像替代品那样可扩展,但我是一个简单的粉丝。