我有一段代碼導致 Node 記錄 UnhandledPromiseRejectionWarning。但我不確定為什么。代碼如下:
export class Hello {
async good(): Promise<string> {
let errorP = this.throwError();
let responseP = this.doSomething();
let [error, response] = await Promise.all([errorP, responseP]);
return response '123';
}
async bad(): Promise<string> {
let errorP = this.throwError();
let responseP = this.doSomething();
let response = (await responseP) '123';
let error = await errorP;
return response;
}
private async throwError(): Promise<string> {
await (new Promise(resolve => setTimeout(resolve, 1000)));
throw new Error('error');
}
private async doSomething(): Promise<string> {
await (new Promise(resolve => setTimeout(resolve, 1000)));
return 'something';
}
}
呼叫try { await hello.bad(); } catch (err) {}導致節點記錄 UnhandledPromiseRejectionWarning
呼叫try { await hello.good(); } catch (err) {}不會記錄警告
完整錯誤:
(node:25960) UnhandledPromiseRejectionWarning: Error: error
at Hello.<anonymous> (C:\hello-service.ts:19:11)
at Generator.next (<anonymous>)
at fulfilled (C:\hello-service.ts:5:58)
at runNextTicks (internal/process/task_queues.js:58:5)
at listOnTimeout (internal/timers.js:523:9)
at processTimers (internal/timers.js:497:7)
(node:25960) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch()
. To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)
(node:25960) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
{"level":30,"time":1639745087914,"pid":25960,"hostname":"AZWP10801-12","reqId":"req-1","dd":{"trace_id":"2081604231398834164","span_id":"2081604231398834164","service":"@amerisave/example-service","version":"0.0.0"},"res":{"statu
sCode":200},"responseTime":1025.4359999895096,"msg":"request completed"}
(node:25960) PromiseRejectionHandledWarning: Promise rejection was handled asynchronously (rejection id: 1)
一些依賴版本:節點版本。14.16.1 ts-node-dev 版本。1.1.8 ts 節點版本。9.1.1 打字稿版本。4.5.2
為什么good好,但bad壞?
uj5u.com熱心網友回復:
問題bad()是因為errorP承諾在您到達之前拒絕await errorP,因此當沒有拒絕處理程式到位時它拒絕。Nodejs 檢測到一個被拒絕的承諾,你的行程回傳到事件回圈,并且被拒絕的承諾沒有拒絕處理程式。這會得到“未處理的拒絕”警告。
請注意,雖然await errorP不直接應用拒絕處理程式,但它確實將 errorP 系結到async具有拒絕處理程式的父函式,因此await errorP間接將拒絕處理分配給errorP. 而errorP它本身只會拒絕并且不會導致父async函式發生任何事情。它只是一個變數,包含一個現在被拒絕的承諾,上面沒有拒絕處理程式。
要利用async被拒絕承諾的自動錯誤傳播,您必須遵守await該承諾。
Nodejs 不知道您await將來會添加將在未來某個時間執行的代碼,因此它會報告未處理的拒絕。
代碼會受到這些型別的錯誤的影響,在這種情況下,您將承諾放入變數中,并且您沒有任何型別的承諾的拒絕處理程式,然后await在您將任何型別的拒絕處理程式置于先前的承諾之前,您繼續執行其他承諾。承諾只是坐在那里,沒有錯誤處理。如果由于時間原因,它恰好在該狀態下拒絕,您將收到警告。通常的解決方法是:
- 立即對 Promise 進行錯誤處理,這樣它就不會單獨存在。
- 在您準備好使用它之前不要創建承諾,但是您將使用它進行適當的錯誤處理(使用 a
.then().catch()或 in aPromise.all().catch()或 inawait或其他)。 - 不要
await在承諾位于變數中而沒有任何拒絕處理的情況下進行其他承諾。
我發現如果我可以避免將一個完全沒有處理的承諾放入一個變數中,而只是將承諾創建到將被監控完成和錯誤的情況下,你甚至不必通常認為關于這個問題。
僅供參考,如果您在 nodejs 中運行它,您可以在此處以更簡單的方式添加拒絕處理程式之前說明承諾拒絕的相同一般概念:
function bad(t) {
return new Promise((resolve, reject) => {
setTimeout(reject, t);
});
}
const b = bad(500);
// this timer will fire after bad() rejects
setTimeout(() => {
b.catch(err => {
console.log("caught b rejection");
})
}, 600);
您將收到“未捕獲的拒絕”錯誤,因為當承諾拒絕時,它還沒有.catch()處理程式。您的代碼有同樣的問題(雖然有點模糊),因為拒絕處理程式來自await和async函式以及函式try/catch的呼叫者async正在使用。
uj5u.com熱心網友回復:
這是一個假設(可以通過實驗證明)。
good和之間的行為差??異bad可以通過awaits的順序來解釋。
在bad您等待 onthrowError之后您正在等待中doSomething,而在 中good,您正在等待 on Promise.all,直到兩者都已滿或至少一個被拒絕(這里就是這種情況)才會回傳。
所以bad,投擲正在發生的事情之外的await,和你catch沒有被觸發,它是由節點內部抓獲。
如果你改變你,bad讓你先await打開throwError,那么你的捕獲將被觸發:
async bad(): Promise<string> {
let errorP = this.throwError();
let responseP = this.doSomething();
let error = await errorP;
let response = (await responseP) '123';
return response;
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/386093.html
