简体   繁体   English

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

[英]Node.js - how to call a Facebook API within a for loop without exceeding rate limit?

I have an array with almost 2 millions of Facebook idSender, and I want to itearate over it, calling a Facebook API for each one of them. 我有一个包含将近200万个Facebook idSender的数组,我想对其进行迭代,为每个API调用一个Facebook API。 Now, due to the asynchronicity, if I launch a simple for loop, Facebook would return me a rate limit exceed error after 4-5 minutes. 现在,由于异步性,如果我启动一个简单的for循环,Facebook将在4-5分钟后向我返回一个速率超过限制的错误。 After some attempts I found out that the ideal delay to avoid rate limit is 20 milliseconds. 经过一些尝试,我发现避免速率限制的理想延迟是20毫秒。

So I tried this solution: I wrapped my function in a Promise, and I used setTimeout to set a delay. 因此,我尝试了以下解决方案:我将函数包装在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)

but this solution it's not working, and I'm also aware it's almost never a good idea using setTimeout fuction to manipulate asynchronicity in Javascript, in fact I can't even say what exactly it's happening there. 但是此解决方案无法正常工作,而且我也意识到使用setTimeout功能来操纵Javascript中的异步性从来都不是一个好主意,实际上,我什至无法确切说明它在那里到底发生了什么。

Any suggestion for possible modifies to my function? 有任何可能修改我功能的建议吗? Any idea on a totally new implementation that could work? 有什么想法可以实现一个全新的实现吗? Thanks 谢谢

Just await a time inside the for loop: 只是在for循环中await一段时间:

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

You may also do something like this with promises; 您也可以通过诺言做这样的事情;

 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 } 

Alternatively, using setTimeout with promises can also be used: 另外,也可以将setTimeout与promises一起使用:

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

Fairly strait-forward, it maps each value to a check() call with a delay of 20n ms for each subsequent request. 相当困难,它将每个值映射到一个check()调用,每个后续请求的延迟为20n ms。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM