在使用 Promise 時,很容易忘記在異步函式中使用 try/catch,否則無法捕獲所有可能的錯誤。這會導致無休止的“等待”,即 Promise 永遠不會被解決或拒絕。
如果存在未捕獲的錯誤,是否有任何方法(例如通過代理或更改承諾建構式)導致異步函式或其他承諾被拒絕?下面顯示一個一般情況。我正在尋找某種方法來通過“等待”(如在拋出錯誤時應該拒絕“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
}
})();```
uj5u.com熱心網友回復:
可能有一種方法可以做到這一點,但在你的情況下,我認為你真的想reject在你的 Promise 中使用該函式而不是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
}
})();
uj5u.com熱心網友回復:
在未捕獲的同步錯誤的情況下,Promise 已經拒絕:
- 在 Promise 建構式中,用于同步(拋出)錯誤
如果在 executor 中拋出錯誤,則 promise 被拒絕。
- in
onFulfilled和onRejected函式,例如 inthen和catch如果處理函式:[...] 拋出錯誤,則回傳的承諾將
then被拒絕,并以拋出的錯誤作為其值。 - 在
async函式中回傳值: A
Promise將使用異步函式回傳的值決議,或因異步函式拋出或未捕獲的例外而被拒絕。
您的問題不是 Promise 不處理未捕獲的錯誤,而是從根本上說因為您的錯誤是異步的:就 Promise 而言,它的 executor 函式是一個成功的小函式,它呼叫setTimeout. 當您的setTimeout處理程式運行并失敗時,它會使用與 Promise 物件或其函式無關的自己的堆疊來執行此操作;除了處理程式通過閉包包含的參考之外,與您的處理程式無關badPromise或p不存在任何內容。與問題“處理來自 setTimeout 的錯誤”一樣,在處理程式中捕獲錯誤的技術都涉及編輯或包裝處理程式,并且根據計時器的 HTML 規范setTimeoutressetTimeout步驟 9.2 沒有機會捕獲或插入錯誤案例來呼叫傳遞給setTimeout.
除了編輯之外badPromise,您幾乎無能為力。
setTimeout(我能想到的唯一選擇是依次修改/覆寫 Promise 建構式和方法,包裝 Promise 建構式的方法以保存resolve/reject引數,然后包裝全域setTimeout方法,以便用呼叫的/包裝setTimeout處理程式新保存的引數。由于更改兩個全域服務的脆弱性,我強烈建議不要使用這樣的任何解決方案。)trycatchreject
uj5u.com熱心網友回復:
根本問題是計時器回呼作為頂級代碼運行,檢測其中錯誤的唯一方法是偵聽全域錯誤事件。這是一個使用全域處理程式來檢測此類錯誤的示例,但它存在一些問題,我將在下面的代碼中討論:
"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 one rror;
let errorArgs = null;
let pError = new Promise( (res, rej)=> {
one rror = (...args) => rej( args); // error handler rejects pError
window.addEventListener("error", one rror);
})
.catch( args => errorArgs = args); // Catch handler resolves with error args
// race between badPromise and global error
await Promise.race( [badPromise(), pError] );
window.removeEventListener("error", one rror); // 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. - 示例中出現的任何錯誤事件都可以贏得承諾競賽
window。它不必在badPromise()呼叫中生成。 - 如果多個呼叫同時
badPromise處于活動狀態,則捕獲全域錯誤不會告訴您哪個badPromise呼叫出錯。
因此badPromise真的很糟糕,需要用小手套處理。如果您嚴重無法修復它,您可能需要確保您只有一個未完成的呼叫,并且您沒有做任何其他可能同時產生全域錯誤的操作。在你的情況下這是否可能不是我可以評論的。
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/421503.html
標籤:
