我正在请求服务器“ S”获取一些数据,但是此数据可能尚未准备好。
当数据尚未准备好时,服务器S会以{"data":null,"state": "pending"}
进行响应,但是在准备好数据后,响应将类似于{"data": {...somedata}, "state": "done"}
。
我必须重复请求,直到数据准备就绪。我现在正在做的事情是这样的:
let wait = function* () {
let t = 500;
for (let j = 1; j < 10; j++) {
yield new Promise((resolve) => {
setTimeout(() => resolve(), t*=2);
});
}
}();
let result = await sendRequestToS();
status = result;
for (let i = 0; i < 4 && result.state==='pending'; i++) {
await wait.next().value;
result = await sendRequestToS();
}
如您所见,我最多发送4次请求,延迟为1、2、4和8秒。
我这样做正确吗? (使用 setTimeout 延迟请求之间的时间)不是不好的做法吗?
答案 0 :(得分:1)
我会这样写:
function wait(ms) {
return new Promise(res => setTimeout(res, ms));
}
async function requestAndRetry() {
let retries = 10;
let timeout = 1000;
while(retries>0) {
const response = await sendRequestToS();
if (result?.state === 'done') {
return result;
}
await wait(timeout);
retries--;
timeout*=2;
}
throw new Error('Request failed after 10 retries');
}
我认为这不是一个坏主意。这称为指数补偿,您并没有阻止脚本引擎。
答案 1 :(得分:0)
您可以直接使用async/await
和递归来代替直接使用生成器。这是一个示例,它尝试获取有限次数的响应,以防止无限递归并且重试之间超时:
async function wait(timeInMs) {
console.log('Waiting ...');
return new Promise((resolve => setTimeout(() => resolve(), timeInMs)));
}
async function tryRequestToS(numberOfTries, timeout) {
if (numberOfTries <= 0) {
throw new Error("could net get result");
}
const result = await sendRequestToS();
if (result && result.state === "done") {
return result;
}
await wait(timeout); // wait for the defined timeout before recurring
return tryRequestToS(numberOfTries - 1, timeout);
}
(async () => {
try {
const result = await tryRequestToS(10, 500); // max. 10 retries, 500 ms delay between retries
console.log(result);
} catch(err) {
console.log(err);
}
})();