舉個栗子,如果用戶在沒有登陸的條件下調用接口,那么所有接口都應該返回一個狀態碼表示用戶沒有登陸,此時需要跳轉到登陸頁進行登陸。
但是如果每次調用接口都需要判斷一下,代碼就會顯得十分冗余,因此我們定義了一個apAjax.js,核心代碼如下:
const apAjax = (options) => {
// 一些配置代碼
return new Promise((resolve, reject) => {
axios({
method: options.method,
url: options.url,
data: options.data,
...
}).then((res) => {
resolve(res)
if(res.code == 401) {
// 跳轉到登陸頁
}
// 其他代碼
}).catch((error) => {
reject(error)
})
})
}
調用
import apAjax from 'apAjax.js'
apAjax(options).then(res => {
// 在這里我們只需要處理接口正常返回的情況即可
// 因為未登陸的情況已經在apAjax.js里面統一處理了
})
看上去代碼更加精簡了,并且在全局有了統一的錯誤處理,但是當我們的項目接入sentry日志監控之后,卻收到了下圖的報錯信息
明明在封裝的apAjax函數里面進行了catch錯誤捕獲,為什么還會報錯呢?
可以看到我們axios函數的then方法里面第一行代碼就是resolve(res)
,這時候Promise的狀態已經變成了resolved
,這種改變是不可逆的,此時就算后面的其他代碼拋出異常,也不會被catch方法捕獲到。
另外,Promise對象的錯誤還有“冒泡”的性質,會一直向后傳遞,直到被捕獲為止。但是上面的調用代碼只有then
沒有catch
。(以為被全局統一捕獲了,所以沒寫)最終誕生了這個無家可歸的異常。
不僅如此, Promise之間涇渭分明,內部Promise拋出的任何錯誤,外部Promise對象都無法感知并捕獲。 同時,由于promise是異步的,try catch語句也無法捕獲其錯誤。
因此養成良好習慣,不要偷懶,每一個Promise都請記得寫上catch。