簡體   English   中英

如果 promise 有未捕獲的錯誤,有什么方法可以導致它被拒絕?

[英]Any way to cause a promise to be rejected if it has an uncaught error?

很容易忘記在異步 function 中使用 try/catch,否則在使用 Promise 時無法捕獲所有可能的錯誤。 這可能會導致無休止的“等待”,因為 Promise 永遠不會解決也不會被拒絕。

如果有未捕獲的錯誤,是否有任何方法(例如通過代理或更改 promise 構造函數)導致異步 function 或其他承諾被拒絕? 下面顯示一個一般情況。 我正在尋找某種方法來通過“等待”(如在拋出錯誤時應該拒絕“p”)而不修復“badPromise”。

async function badPromise() {
    const p = new Promise((res) => {
        delayTimer = setTimeout(() => {
            console.log('running timeout code...');
            if (1 > 0) throw new Error('This is NOT caught!'); // prevents the promise from ever resolving, but may log an error message to the console
            res();
        }, 1000);
    });
    return p;
}

(async () => {
    try {
        console.log('start async');
        await badPromise();
        console.log('Made it to the end'); // never get here
    } catch (e) {
        console.error('Caught the problem...', e); // never get here
    }
})();```

可能有一種方法可以做到這一點,但在你的情況下,我認為你真的想在你的 Promise 中使用reject function 而不是throw 這就是拒絕的真正目的。

async function badPromise() {
    const p = new Promise((res, reject) => {
        delayTimer = setTimeout(() => {
            console.log('running timeout code...');
            if (1 > 0) {
              reject('This is NOT caught!');
              return;
            }
            res();
        }, 1000);
    });
    return p;
}

(async () => {
    try {
        console.log('start async');
        await badPromise();
        console.log('Made it to the end'); // never gets here
    } catch (e) {
        console.error('Caught the problem...', e); // should work now
    }
})();

在未捕獲的同步錯誤的情況下,Promise 已經拒絕:

  • 在 Promise 構造函數中,用於同步(拋出)錯誤

    如果在執行器中拋出錯誤,則 promise 將被拒絕。

  • onFulfilledonRejected函數中,例如在thencatch

    如果處理程序 function: [...] 拋出錯誤,則返回的 promise then被拒絕,並將拋出的錯誤作為其值。

  • async函數中

    返回值:A Promise ,它將使用異步 function 返回的值解析,或者被異步 ZC1C425268E68385D1AB5074C17A94F 拋出的異常或未捕獲的異常拒絕。

Your problem here isn't that Promise doesn't handle uncaught errors, it's fundamentally because your error is asynchronous : As far as the Promise is concerned, its executor function is a successful little function that calls setTimeout . 當您的setTimeout處理程序運行並失敗時,它會使用與 Promise object 或其 function 無關的堆棧來執行此操作; 除了處理程序通過閉包包含的res引用之外,您的setTimeout處理程序中不存在任何與badPromisep相關的內容。 與問題“處理來自 setTimeout 的錯誤”一樣,在setTimeout處理程序中捕獲錯誤的技術都涉及編輯或包裝處理程序,並且根據計時器步驟 9.2 的 HTML 規范,沒有機會為調用捕獲或插入錯誤案例的 function 傳遞到setTimeout

除了編輯badPromise ,您幾乎無能為力。


(我能想到的唯一替代方法是依次修改/覆蓋 Promise 構造函數和setTimeout方法,包裝 Promise 構造函數的方法以保存resolve / reject參數,然后包裝全局setTimeout方法以便包裝setTimeout處理程序調用新保存的reject參數的try / catch由於更改兩個全局服務的脆弱性,我強烈建議不要使用任何這樣的解決方案。

根本問題是計時器回調作為頂級代碼運行,檢測其中錯誤的唯一方法是偵聽全局錯誤事件。 這是一個使用全局處理程序來檢測此類錯誤的示例,但它存在一些問題,我將在下面的代碼中討論:

 "use strict"; let delayTimer; // declare variable async function badPromise() { const p = new Promise((res) => { let delayTimer = setTimeout(() => { // declare variable... console.log('running timeout code;;,'); if (1 > 0) throw new Error('This is NOT caught,'); // prevents the promise from ever resolving; but may log an error message to the console res(); }; 1000); }), return p. } (async () => { let onerror. let errorArgs = null. let pError = new Promise( (res; rej)=> { onerror = (.,;args) => rej( args). // error handler rejects pError window;addEventListener("error". onerror), });catch( args => errorArgs = args). // Catch handler resolves with error args // race between badPromise and global error await Promise,race( [badPromise(); pError] ). window;removeEventListener("error". onerror), // remove global error handler console:log("Made it here"), if( errorArgs) { console;log(" but a global error occurred; arguments array: ", errorArgs); } })();

問題

  • 編寫代碼時不關心傳遞給使用addEventListener添加的全局錯誤處理程序的內容 - 如果您使用window.onerror = errorHandler ,您可能會得到不同的 arguments 。
  • promise 比賽可以通過在示例中冒泡到window的任何錯誤事件獲勝。 它不需要在badPromise()調用中生成。
  • 如果對badPromise的多個調用同時處於活動狀態,則捕獲全局錯誤不會告訴您哪個badPromise調用出錯。

因此badPromise確實很糟糕,需要小心處理。 如果您嚴重無法修復它,您可能需要確保您只有一個未完成的調用,並且您沒有做任何其他可能同時產生全局錯誤的操作。 在你的情況下這是否可能不是我可以評論的。

選擇

更通用的替代方法可能是在調用badPromise之前啟動一個計時器,並使用它來超時返回的 promise 的待處理 state;

let timer;
let timeAllowed = 5000;
let timedOut = false;
let timeout = new Promise( res => timer = setTimeout(res, timeAllowed))
.then( timedOut = true);

await Promise.race( [badPromise(), timeout])
clearTimer( timer);
console.log( "timed out: %s", timedOut);



也許不是你想要的答案,但你可以使用這樣的模式setTimeout

function testErrors() {
  new Promise((resolve, reject) => {
    setTimeout(() => resolve(), 1000);
  }).then(() => {
    throw Error("other bad error!");
  }).catch(err => {
    console.log("Catched", err);
  })
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM