如何减慢这个节点循环http请求?

我正在尝试使用Lambda函数使用请求模块大约200-300次调用此API。 我需要在每个呼叫之间加上第二个,所以我没有得到429响应。 我已经尝试了几种不同的方法来实现这一点,但似乎忽略了使代码变慢的代码。

人们通常如何减缓AWS lambda中的这些请求? 如果我可以在循环中插入诸如utilities.sleep(1000)之类的东西,使其等待一秒钟,然后再继续,那将是非常好的。 我相信这个问题有一个简单的解决scheme,但是我所见过的所有例子似乎都使它变得复杂。

function findProjects(items){ var toggleData = []; for( var i = 0; i < items.length; i++ ){ setTimeout( callToggle( items[i] ), 1000 ); } function callToggle( data ){ request({ 'url': 'https://www.toggl.com/api/v8/projects/' + data.toggle.data.id, 'method': 'GET', 'headers': { 'Content-Type': 'application/json', 'Accept': 'application/json' }, 'auth': { 'user': 'xxxxxxx', 'pass': 'api_token' }}, function( error, response, body ){ if( error ) { console.log( error ); context.done( null, error ); } else { console.log(response.statusCode, "toggle projects were listed"); var info = JSON.parse(body); toggleData.push(info); } }); } findDocument( toggleData ); } 

虽然Node.js是单线程的,但setTimeout不会创build一个同步调用的堆栈。 当您使用for循环时,您立即将每个后续呼叫设置为提前1000毫秒,以便大致同时启动。 相反,您可能希望使用第三方的promise lib等待。

你可以做一些简单的事情:

 const Bluebird = require('bluebird'); const $http = require('http-as-promised'); const _ = require('lodash'); const timeout = 1000; const items = []; const headers = { 'Content-Type': 'application/json', 'Accept': 'application/json' }; const auth = { 'user': 'xxxxxxx', 'pass': 'api_token' }; const makeRequest = (id) => { const url = 'https://www.toggl.com/api/v8/projects/' + id; return $http.get({ url, headers, auth }); }; const waitCall = (data) => { return Bluebird .resolve(makeRequest(data.toggl.data.id)) .wait(timeout); }; Bluebird.mapSeries(items, waitCall); 

http://bluebirdjs.com/docs/api/promise.mapseries.html

你可以做这样的事情:

 for(var i = 0; i<items.length; i++){ setTimeout(callToggl, 1000 + (( i * X ) % Y), items[i]); } 

Y是最大延迟(1000 + Y)那么你需要(5秒), X是每个呼叫的时间( X=10 :1000,1010,1020,1030,…)

如果你想每个电话1s:

 for(var i = 0; i<items.length; i++){ setTimeout(callToggl(items[i]), 1000 + ( i * 1000 )); } 

编辑

 for(var i = 0; i<items.length; i++){ setTimeout(callToggl, 1000 + ( i * 1000 ), items[i]); } 

正如你可能知道的,JavaScript代码不会阻塞在io上(除非使用特定的同步api来阻止你的整个代码,这是一个不好的做法,应该避免,除非你有一个很好的理由来阻止整个代码(启动时加载configuration文件…等…))

所以你需要做的只是等待回应

过去曾经有过一些复杂的工作,但是现在使用–harmony标志(激活节点中最新的js特性),你可以使用shiny的新的asynchronous函数语法。 (AWAIT /asynchronous)

你在里面运行的函数必须声明为asynchronous,然后在每次迭代之后,你需要使用“await”关键字等待那个http调用的响应。 这个关键字使代码看起来好像阻塞了,等待解决的答案,尽pipe它不是。

我使用“取”而不是“请求”,因为它与asynchronous函数(基于承诺)很好,但只要您返回承诺,您可以使用任何其他方法。 (你甚至可以promiseify你现有的基于API的Promise对象,但它会使一切看起来更丑陋,所以请不要:))

这里是修改的代码。 我不确定它是否按原样工作。 但是我想这个想法很清楚。

在任何情况下,如果你没有使用asynchronous函数,它是学习如何使用asynchronous函数的一个很好的机会,它们让生活更轻松。

 //making enture function async, so you can use 'await' inside it async function findProjects(items){ var toggleData = []; for( var i = 0; i < items.length; i++ ){ //setTimeout( callToggle( items[i] ), 1000 ); //instead of using a timeout, you need to wait for response before continuing to next iteration await response = callToggle(items[i]); toggleData.push(JSON.parse(response.body)); } async function callToggle( data ){ /*request({ 'url': 'https://www.toggl.com/api/v8/projects/' + data.toggle.data.id, 'method': 'GET', 'headers': { 'Content-Type': 'application/json', 'Accept': 'application/json' }, 'auth': { 'user': 'xxxxxxx', 'pass': 'api_token' }}, function( error, response, body ){ if( error ) { console.log( error ); context.done( null, error ); } else { console.log(response.statusCode, "toggle projects were listed"); var info = JSON.parse(body); toggleData.push(info); } });*/ // to make things simpler, use fetch instead of request which is promise based var myInit = { 'method': 'GET', 'headers': { 'Content-Type': 'application/json', 'Accept': 'application/json' }, 'auth': { 'user': 'xxxxxxx', 'pass': 'api_token' } }; return fetch("https://www.toggl.com/api/v8/projects/",myInit); } findDocument( toggleData ); } 

您可以将请求链接在一起:

 function findProjects(items){ var toggleData = []; // chain requests with delay items.reduce(function (requestChain, item) { return requestChain .then(callToggle.bind(null, item)) .then(wait.bind(null, 1000)); }, Promise.resolve()); function wait (ms) { return new Promise(function (resolve, reject) { setTimeout(resolve, ms); }); } function callToggle(data) { request({ 'url': 'https://www.toggl.com/api/v8/projects/' + data.toggle.data.id, 'method': 'GET', 'headers': { 'Content-Type': 'application/json', 'Accept': 'application/json' }, 'auth': { 'user': 'xxxxxxx', 'pass': 'api_token' }}, function( error, response, body ){ if( error ) { console.log( error ); context.done( null, error ); } else { console.log(response.statusCode, "toggle projects were listed"); var info = JSON.parse(body); toggleData.push(info); } }); } findDocument( toggleData ); }