【问题标题】:Combining Promise.all with rate-limited calls to an API将 Promise.all 与对 API 的限速调用相结合
【发布时间】:2021-02-28 02:02:14
【问题描述】:

我正在仅客户端环境中编写 Javascript,调用速率受限的服务的 API。我的环境只允许我使用 LazyLoad.js 加载 JS 库,这并不适用于所有事情。我已经成功地能够使用节流队列来限制我的 API 请求。但是我无法将它与利用 Promise.all 结合起来检查一系列 API 调用何时完成。如果我省略节流,它会起作用,但不会。

如何将这两者结合起来?到目前为止,我想出的唯一方法似乎很笨拙,是使用 setTimeout 为每个调用手动限制速率。然后我发现在检查 Promises.all 之前我需要等待总时间(例如每次调用 200 毫秒),否则前几个 Promises 解决得太快了。这是我所拥有的:

var deferreds = [];
$.each(evalTempQuestions, function(idx, evalTempQuestion){
  setTimeout(function(){
    deferreds.push(knackAPI('POST', 116, 75, evalTempQuestion.payload));
  }, 200 * idx);
});

setTimeout(function(){
  Promise.all(deferreds).then(function(r) {
    console.log('done');
  }).catch(function(err){
    console.log(err);
  });
}, 200 * evalTempQuestions.length);

我怎样才能做得更好?

【问题讨论】:

  • 不要异步推送延迟,而是立即推送您将异步解决的延迟。
  • 您可以在此答案中查看rateLimitMap() 函数:Choose proper async method for batch processing for max requests/sec。它可以让您指定每秒请求的数量和飞行中请求的最大数量,然后在发送请求时进行管理。
  • @bergi 谢谢,这听起来是个好主意 - 你能解释一下我将如何修改代码来做到这一点吗?

标签: javascript promise throttling


【解决方案1】:

我了解到您希望按顺序解析 deferreds。如果是这样,您可以通过多种方式进行操作。其中之一是使用forawait

// Helper to await for setTimeout
const delay = async (millis) =>
  new Promise(resolve => setTimeout(resolve, millis));

// Construct `deferreds` using `map` on `evalTempQuestions`
const deferreds = evalTempQuestions
  .map( evalTempQuestion =>
    // Wrap each request into a function, which will be called
    // sequentially and rate-limited

    // If you want to have both the payload and its results
    // available during post-processing, you can do something like:
    // () => {
    //   const {payload} = evalTempQuestion;
    //   return {
    //     payload,
    //     result: knackAPI('POST', 116, 75, payload)
    //   }
    // }
    () => knackAPI('POST', 116, 75, evalTempQuestion.payload) );

const result = [];
for (const next of deferreds) {
  try {
    // Call the wrapper function, which returns `knackAPI` Promise,
    // which probably is the Promise returned by a `fetch`
    const value = await next();
    // If you use the payload+result way, you'll need something like this:
    // const value = await next.result();
    result.push(value);
  } catch(err) {
    console.log(err);
    result.push(null); // <- Depends on what you need to do
  }

  // Rate limit
  await delay(200);
}
console.log('done');

您可以查看更多示例 herehere(或在搜索引擎中找到的许多其他示例)。

【讨论】:

  • 谢谢。不,我不在乎它们以什么顺序解决,我只想知道它们什么时候全部完成。
  • 但是你说请求之间应该有200ms的间隔...
  • 是的,它需要进行速率限制,但顺序无关紧要。这仍然意味着“按顺序”吗?
  • 是的,它仍然是连续的。
  • @ericalderman 如果这有帮助,请将答案标记为正确答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-17
  • 1970-01-01
  • 2013-04-23
  • 2016-09-12
  • 2019-08-21
  • 2018-06-12
相关资源
最近更新 更多