将 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
。如果是这样,您可以通过多种方式进行。其中之一是使用 for
和 await
:
// 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');
我正在仅客户端环境中编写 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
。如果是这样,您可以通过多种方式进行。其中之一是使用 for
和 await
:
// 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');