簡體   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