代碼
const longTask = async (id, time = 3000, throwError = false) => {
await new Promise((resove) => setTimeout(resove, time));
if (throwError) throw "throwError";
return `longTask finish ${id}`;
};
(async () => {
try {
console.log("start");
const task1 = longTask("1", 3000, true);
const task2 = longTask("2", 3000, false);
console.log(await task2);
console.log(await task1);
console.log("finish");
} catch (error) {
console.log(error);
}
})();
問題根源
問題的根源在於競爭條件 (Race Condition):
task1
和task2
這兩個非同步任務被同時啟動。task1
被設定為在 3 秒後會拋出錯誤 (reject),而task2
會在 3 秒後成功 (resolve)。- 程式碼接著執行
await task2;
,這會讓主程式暫停執行,並等待task2
完成。 - 關鍵點: 在主程式等待
task2
的這 3 秒鐘內,task1
的計時器也到時了,導致task1
這個 Promise 物件的狀態變為rejected
。 - 在
task1
被拒絕的那一刻,您的程式碼還停在await task2;
這一行,尚未執行到await task1;
。因此,對於 Node.js 執行環境來說,task1
的拒絕事件在當下是「沒有被處理」的。 - 在新版的 Node.js 中,任何未被處理的 Promise 拒絕預設會被視為一個致命錯誤,從而導致整個應用程式程序終止。這就是為什麼您會看到程式崩潰,而不是預期地進入
catch
區塊。