[英]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 將被拒絕。
onFulfilled
和onRejected
函數中,例如在then
和catch
如果處理程序 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
處理程序中不存在任何與badPromise
或p
相關的內容。 與問題“處理來自 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 。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.