繁体   English   中英

如何编写超时的异步(基于承诺)function?

[英]How to write an asynchronous (promise-based) function that times out?

我想要 function 可以做一些工作,如果某些条件为真,则解决 promise。 如果没有,请稍等(让我们说一秒钟)然后再试一次。 除此之外,如果时间限制到期,promise 将拒绝。 我怎么能那样做? 看看我的代码示例...如果我包装整个 function 以返回 new Promise(),我不能在其中使用 await(我需要...如果条件失败,我需要睡觉一段时间,而且我需要等待我在函数结束时等待)。

这是我的代码示例:

async funcWithTimeLimit(numberToDecrement, timeLimit){
    let sleep = undefined;
    let timeLimitTimeout = setTimeout(() => { 
        if (sleep)
            clearTimeout(sleep); 
        return Promise.reject("Time limit of " + (timeLimit/1000) +" secs expired"); //reject
    }, timeLimit);

    while(numberToDecrement > 0){
        for(let i = 10;(i > 0 && numberToDecrement > 0); i--){ //Do some work
            numberToDecrement--;
        }

        if(numberToDecrement > 0){
            await new Promise(resolve => sleep = setTimeout(resolve, 1000));
        }
    }

    clearTimeout(timeLimitTimeout);
    await new Promise((resolve, reject) => sleep = setTimeout(resolve, 500)); // Do something
    return ""; //resolve
}

注意:我最大的问题是 - 我如何编写这个 function 以便能够在时间限制到期的情况下捕获拒绝(在我调用funcWithTimeLimit()的地方)?

有两种基本方法。 一种是重复检查时间并在达到限制后抛出异常,另一种是每个await ed promise 与 timeout 竞争 第三种将需要您启动的异步任务的合作,如果它们为您提供一种在其界面中取消它们的方法,则只需将检查超时的任务卸载给它们。

在它们中,您都不能通过从setTimeout抛出异常来拒绝async function

  1. 相当简单:

     function doSomething() { return new Promise((resolve, reject) => { setTimeout(resolve, 500)); // Do something } } async funcWithTimeLimit(numberToDecrement, timeLimit) { while (numberToDecrement > 0) { for (let i = 10; i > 0 && numberToDecrement > 0; i--) { if (Date.now() > timelimit) throw new TimeoutError("Exceeded limit"); // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ numberToDecrement--; // Do some work } if (numberToDecrement > 0) { if (Date.now() + 1000 > timelimit) throw new TimeoutError("Exceeded limit"); // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ await new Promise(resolve => setTimeout(resolve, 1000)); } } // but ineffective here: await doSomething(); return ""; }
  2. 赛车:

     async funcWithTimeLimit(numberToDecrement, timeLimit) { const timeout = new Promise((resolve, reject) => { setTimeout(() => { reject(new TimeoutError("Exceeded limit")); }, timeLimit - Date.now()); }); timeout.catch(e => void e); // avoid unhandled promise rejection if not needed while (numberToDecrement > 0) { for (let i = 10; i > 0 && numberToDecrement > 0; i--) { // no guarding of synchronous loops numberToDecrement--; // Do some work } if (numberToDecrement > 0) { await Promise.race([ timeout, // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ new Promise(resolve => setTimeout(resolve, 1000)), ]); } } await Promise.race([ timeout, // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doSomething(), ]); return ""; }

    请注意,如果当 function 已经完成时, setTimeout会保持事件循环打开,我们只是忽略拒绝的 promise。 更好但更费力的是在我们不再需要超时时取消它:

     async funcWithTimeLimit(numberToDecrement, timeLimit) { let timer; const timeout = new Promise((resolve, reject) => { timer = setTimeout(() => { reject(new TimeoutError("Exceeded limit")); }, timeLimit - Date.now()); }); try { // as before: while (numberToDecrement > 0) { for (let i = 10; i > 0 && numberToDecrement > 0; i--) { numberToDecrement--; // Do some work } if (numberToDecrement > 0) { await Promise.race([ timeout, new Promise(resolve => setTimeout(resolve, 1000)) ]); } } await Promise.race([ timeout, doSomething() ]); return ""; } finally { clearTimeout(timer); // ^^^^^^^^^^^^^^^^^^^^ } }
  3. 与被称为 function 的合作当然更好:

     function delay(t, limit) { if (Date.now() + t > timelimit) throw new TimeoutError("Exceeded limit"); return new Promise(resolve => setTimeout(resolve, t)); } function doSomething(limit) { return new Promise((resolve, reject) => { const timeout = setTimeout(() => { xhr.cancel(); // custom API-dependent cancellation reject(new TimeoutError("Exceeded limit")); }, limit - Date.now()); const xhr = someApiCall(); // Do something xhr.onerror = err => { clearTimeout(timeout); reject(err); }; xhr.onload = res => { clearTimeout(timeout); resolve(res); }; } } async funcWithTimeLimit(numberToDecrement, timeLimit) { while (numberToDecrement > 0) { for (let i = 10; i > 0 && numberToDecrement > 0; i--) { numberToDecrement--; // Do some work } if (numberToDecrement > 0) { await delay(1000, timeLimit); // ^^^^^^^^^ } } await doSomething(timeLimit); // ^^^^^^^^^ return ""; }

当然,您可以(在适用的情况下)并且应该(在合理的情况下)结合这些方法。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM