始終捕捉 Promise 中的錯誤的重要性
P粉590929392
P粉590929392 2024-03-19 21:05:20
0
1
409

我在我的專案中使用 @typescript-eslint/no-floating-promises 規則。如果我寫這樣的程式碼,這條規則就會抱怨 -

functionReturningPromise()
    .then(retVal => doSomething(retVal));

它希望我為此 Promise 添加一個 catch 區塊。如果我想在異常處理區塊中添加一些邏輯,這對我來說是有意義的。但是,在很多情況下我不需要它。我對拋出的錯誤很滿意。因此,為了抑制此規則引發的錯誤,我最終這樣做了 -

functionReturningPromise()
    .then((retVal) => doSomething(retVal))
    .catch((error) => {
        throw error;
    });
即使我沒有像上面那樣添加 catch 區塊,error 仍然會以相同的方式拋出(至少在我的控制台輸出中看到它)。因此,我不明白明確指定此 catch 區塊的意義。我錯過了什麼嗎?如果我新增/不新增 catch 區塊,拋出 error 的方式真的有差別嗎?

P粉590929392
P粉590929392

全部回覆(1)
P粉106711425

評論者都很好地回答了您的問題 - 但為了透過範例說明為什麼這很重要,請想像以下程式碼:

Promise.reject();
setTimeout(() => console.log('hello'), 1000);

這段程式碼看起來相當無害 - 有一個未處理的無操作承諾拒絕,啟動後 1 秒程式將記錄 'hello'

在瀏覽器中 - 這正是將會發生的情況 - 瀏覽器將記錄「未捕獲的承諾拒絕」錯誤,但否則會忽略它。

然而,在 NodeJS(從 Node v15 開始)中,未處理的 Promise 拒絕是一個硬錯誤 - 這表示進程在偵測到錯誤時將退出!

您可以透過在終端機中執行程式碼來驗證這一點(-e 的意思是「評估並執行此程式碼字串」)

$ node -e "Promise.reject(); setTimeout(() => console.log('hello'), 1000)"
node:internal/process/promises:288
            triggerUncaughtException(err, true /* fromPromise */);
            ^

[UnhandledPromiseRejection: 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(). The promise rejected the was not handled with .catch(). The promise rejected the
  code: 'ERR_UNHANDLED_REJECTION'
}

Node.js v18.12.1

您可以看到 'hello' 永遠不會被列印,因為進程在 1 秒之前終止!

要驗證事情是否按預期工作,您可以將 .reject 更改為 .resolve

$ node -e "Promise.resolve(); setTimeout(() => console.log('hello'), 1000)"
hello

因此,如果您正在使用任何 LTS 支援的版本編寫 NodeJS 應用程序,那麼您絕對應該處理錯誤,否則您將面臨意外崩潰的風險。

如果您的程式碼僅在瀏覽器中運行,那麼您可能想知道是否應該處理失敗- 畢竟您的用戶沒有查看控制台,因此他們不會知道發生了任何不好的事情,所以誰在乎呢?從“僅代碼”的角度來看,您是正確的 - 但是,當出現問題時,您的用戶希望從他們的應用程式中獲得反饋。

想像以下場景 - 您的 Promise 追蹤 API 呼叫的結果,該呼叫提交用戶在您的應用程式中輸入的一些資料。如果該 API 呼叫由於某種原因失敗,那麼您的應用程式應該做出適當的回應並告訴使用者出了問題。

處理它的替代方法可能意味著您的應用程式顯示無限載入旋轉器,或者使用者認為他們的資料已成功提交,但實際上並未成功。無論哪種方式 - 這是一個非常糟糕且破碎的用戶體驗!

最後做一些像 .catch(e => { throw e }) 這樣的事情,你其實並沒有處理錯誤。當然,這段程式碼會使 linter 保持沉默 - 但您所做的只是創建一個新的、被拒絕的承諾,該承諾將記錄到控制台。相反,您應該以某種方式將錯誤連接到應用程式的 UI,例如像 .catch(e => {alert(e); throw e }) 這樣簡單的東西會更好。

熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板