nodejs中,一段被try...catch包覆,卻還會崩潰的程式


代碼

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):

  1. task1 和 task2 這兩個非同步任務被同時啟動。task1 被設定為在 3 秒後會拋出錯誤 (reject),而 task2 會在 3 秒後成功 (resolve)。
  2. 程式碼接著執行 await task2;,這會讓主程式暫停執行,並等待 task2 完成。
  3. 關鍵點: 在主程式等待 task2 的這 3 秒鐘內,task1 的計時器也到時了,導致 task1 這個 Promise 物件的狀態變為 rejected。
  4. 在 task1 被拒絕的那一刻,您的程式碼還停在 await task2; 這一行,尚未執行到 await task1;。因此,對於 Node.js 執行環境來說,task1 的拒絕事件在當下是「沒有被處理」的。
  5. 在新版的 Node.js 中,任何未被處理的 Promise 拒絕預設會被視為一個致命錯誤,從而導致整個應用程式程序終止。這就是為什麼您會看到程式崩潰,而不是預期地進入 catch 區塊。