Node.js - 如何在不超出速率限制的情况下在for循环中调用Facebook API?

问题描述 投票:1回答:3

我有一个拥有近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中的异步性几乎从来都不是一个好主意,事实上我甚至无法说出它到底发生了什么。

有关可能修改我的功能的任何建议吗?有关全新实施的任何想法都可行吗?谢谢

javascript node.js asynchronous promise
3个回答
2
投票

只是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)
  }
}

0
投票

你也可以用承诺来做这样的事情;

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
}

0
投票

或者,也可以使用带有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。

© www.soinside.com 2019 - 2024. All rights reserved.