将 Promise.all 与对 API 的限速调用相结合

Combining Promise.all with rate-limited calls to an API

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

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

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

我怎样才能做得更好?

我了解到您想按顺序解决 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');

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