Javascript 使用Node.js和Promises实现指数退避
我在代码中对一个API发出了大约70个请求。我得到了一个错误响应,告诉我我一个接一个的请求太快了,我决定使用指数退避的思想来解决这个问题 目前,我的代码是这样的:Javascript 使用Node.js和Promises实现指数退避,javascript,node.js,Javascript,Node.js,我在代码中对一个API发出了大约70个请求。我得到了一个错误响应,告诉我我一个接一个的请求太快了,我决定使用指数退避的思想来解决这个问题 目前,我的代码是这样的: let backoffTime = 1; for (let i = 0; i < fileIds.length; i++) { let fileId = fileIds[i]; getFileName(fileId, auth) .then((name) => { // do
let backoffTime = 1;
for (let i = 0; i < fileIds.length; i++) {
let fileId = fileIds[i];
getFileName(fileId, auth)
.then((name) => {
// do some work
})
.catch((err) => {
// assumes that the error is "request made too soon"
backoff(backoffTime);
backoffTime *= 2;
i--;
console.log(err);
});
}
function backoff(time) {
let milliseconds = time * 1000;
let start = (new Date()).getTime();
while (((new Date()).getTime() - start) < milliseconds) {
// do nothing
}
}
let backoffTime=1;
for(设i=0;i{
//做些工作
})
.catch((错误)=>{
//假设错误为“请求太快”
退避(退避时间);
退避时间*=2;
我--;
控制台日志(err);
});
}
功能回退(时间){
毫秒=时间*1000;
让开始=(新日期()).getTime();
而(((新日期()).getTime()-start)<毫秒){
//无所事事
}
}
MygetFileName
函数向API发出请求并返回承诺
目前这不起作用,因为承诺是异步的(有点)。我的for循环运行得非常快,并调用getFileName函数,这使得那些API请求非常快。然后,它会得到一些API调用的错误,在这种情况下,它会更新backoffTime。这个实现不起作用
你知道我如何正确地实现这一点吗?首先,用一个几乎无限的循环阻塞浏览器是一个非常非常糟糕的主意,只要使用承诺:
const delay = ms => new Promise(res => setTimeout(res, ms));
然后,在继续循环和使用延迟之前,只需等待承诺:
(async function() {
for (let i = 0; i < fileIds.length; i++) {
let fileId = fileIds[i];
await getFileName(fileId, auth)
.then((name) => {
// do some work
})
.catch((err) => {
// assumes that the error is "request made too soon"
backoffTime *= 2;
i--;
console.log(err);
return delay(backoffTime);
});
}
})();
(异步函数(){
for(设i=0;i{
//做些工作
})
.catch((错误)=>{
//假设错误为“请求太快”
退避时间*=2;
我--;
控制台日志(err);
返回延迟(回退时间);
});
}
})();
最简单的方法是使用async/await,然后等待每个请求,或者如果请求太慢,则创建包含15个请求和承诺的块。所有这些块
您还可以使用以下选项:
将承诺转换为回调需要一些额外的工作,反之亦然,但它会做得最好
这是函数:parallelLimit(任务、限制、回调)
const tasks=[];
//这个for循环只是将任务准备到函数数组中
for(设i=0;idoWorkThatReturnsPromise(fileid[i])
.然后(val=>回调(null,val))
.catch(callback));
}
async.parallelLimit(任务,15,(错误,值)=>{
//做完后做点什么
})
您可以使用以下示例修复此问题:
for(设i=0;i{
//做些工作
})
.catch((错误)=>{
设置超时(()=>{
doCall(fileId,(backoffTime*2));
},退避时间*1000);
});
}
您可以使用以下方法修复此问题:我认为OP希望并行运行调用,并在延迟后重新运行失败的调用。您的示例按顺序运行所有调用。您的async
await
是无用的。顺便说一句,您应该使用async
await
和尝试捕获
或删除它们。他们不是。但是格式很差。。。混合。然后
和等待
可能会让人困惑,就像约翰斯·威尔姆斯在他的回答中说的那样:用一个几乎无限的循环阻塞浏览器是一个非常非常糟糕的主意!这需要在火灾中死去。永远,永远,永远,永远不要像这样使用无限循环。它会影响服务器,并且在等待时不会让其他代码运行。请使用冻结主线程来执行此操作。@UpTheCreek我无法删除它,因为它是可接受的答案。提及为什么应该删除它可能对其他人有用。顺便说一句,在我编辑它之前,我得到了大多数(如果不是全部的话)的反对票,这是因为在编辑之前,我的解决方案仍然包括一个阻塞主线程的,而循环。
const tasks = [];
// This for-cycle will just prepare the tasks into array of functions
for (let i = 0; i < fileIds.length; i++) {
tasks.push(callback => doWorkThatReturnsPromise(fileIds[i])
.then(val => callback(null, val))
.catch(callback));
}
async.parallelLimit(tasks, 15, (err, values) => {
// do something after it finishes
})