我有一个拥有近2百万Facebook idSender的数组,我想迭代它,为每一个调用一个Facebook API。现在,由于异步性,如果我启动一个简单的for循环,Facebook会在4-5分钟后返回速率限制超过错误。经过一些尝试后,我发现避免速率限制的理想延迟是20毫秒。
所以我尝试了这个解决方案:我将函数包装在Promise中,并使用setTimeout来设置延迟。
async function asyncLoop(values) {
var prm = await new Promise(function(resolve, reject) {
setTimeout(function() {
for (var i=0; i<values.length; i++) {
check(values[i].idSender, values[i].iscrizione, values[i].id_sito)
if(checked == values.length) {
resolve()
}
}
},20);
});
return prm;
}
asyncLoop(idSenderArray)
但是这个解决方案没有用,而且我也知道使用setTimeout功能来操纵Javascript中的异步性几乎从来都不是一个好主意,事实上我甚至无法说出它到底发生了什么。
有关可能修改我的功能的任何建议吗?有关全新实施的任何想法都可行吗?谢谢
只是await
在for循环中的时间:
const timer = ms => new Promise(res => setTimeout(res, ms));
async function asyncLoop(values) {
for (var i = 0; i < values.length; i++) {
await timer(20);
check(values[i].idSender, values[i].iscrizione, values[i].id_sito)
}
}
你也可以用承诺来做这样的事情;
var apiCall = (url,n) => new Promise((v,x) => setTimeout(v,50,`the result of API call @ ${url} no ${n}`)),
calls = Array(20).fill()
.map((_,i) => new Promise((v,x) => setTimeout(v,20*i))
.then(_ => apiCall("http://facebook.com",i))
.then(v => console.log(`I am doing something with ${v}`)));
.as-console-wrapper{
height: 100%;
max-height: 100% !important
}
或者,也可以使用带有promises的setTimeout:
async function asyncLoop(values) {
let apiCallPromises = values.map((value, index)=> new Promise(resolve=>{
setTimeout(_=>{
check(value.idSender, value.iscrizione, value.id_sito)
resolve()
}, index*20)
}))
return Promise.all(apiCallPromises);
}
相当直接的,它将每个值映射到check()
调用,每个后续请求延迟20n ms。