前端異常類型及捕獲方式


目錄

引子

最近想起這方面的事情,就去花時間查找了相關資料,以下是個人的總結。

異常類型

從使用瀏覽器,瀏覽一個網頁,與網頁進行交互的過程,從用戶的角度想一想會出現那些異常。

首先是使用瀏覽器一般都是基於操作系統,系統自身可能會出現問題,比如內存不夠。這類情況歸為系統異常

正常打開瀏覽器后,訪問網頁的時候,可能沒有網絡,或提示出現服務錯誤等等,這類情況歸為網絡異常

能夠正常訪問網頁后,用戶進行交互時,可能出現一種情況下點擊有效,另一種情況下點擊無效。這類情況歸為應用異常

在上面感性的認知基礎上,下面進一步進行細化。

系統異常

系統異常情況比較少,相關的可能有:

  • 瀏覽器崩潰

網絡異常

網絡異常中,相關的可能有:

  • XMLHttpRequest 請求異常
  • Fetch 請求異常
  • 靜態資源加載異常

應用異常

應用異常可以用 JavaScript 中的錯誤對象體現出來:

  • EvalError : 與 eval() 有關的錯誤。
  • RangeError : 表示這個值不在允許值集或范圍內。
  • ReferenceError : 表示發現一個無效的引用。
  • SyntaxError : 表示發生了解析錯誤。
  • TypeError :當其它類型錯誤都不符合時,TypeError 用於指示一個不成功的操作。
  • URIError :表示用於處理 URI 的函數(encodeURI 或 decodeURl)使用方式與其定義的不兼容。

比較常見的異常可以參考 Top 10 JavaScript errors from 1000+ projects

異常捕獲

瀏覽器都具有某種向用戶報告異常的機制,對於用戶都是隱藏此類信息。對於開發者,一般在控制台可以看到相關信息。

下面看下捕獲異常對應的方法。

try-catch 捕獲

try-catch 使用的形式如下:

try {
  // 可能導致異常的代碼
} catch(error) {
  // 發生異常時的處理
}

測試頁面見這里,有下面的一些特點:

  • catch 塊中會接收一個包含異常信息的對象,在不同的瀏覽器中包含的信息可能不同,但共同有一個保存異常信息的 message 屬性。
  • 不能捕獲語法異常。
  • 不能捕獲異步異常。
  • 該方式捕獲的異常,不會出現在控制台上,也不會被 error 事件捕獲。

語法異常在開發的階段就很容易發現,例如:

try {
  var num = '333;
} catch(error) {
  console.info('try-catch:', error);
}

不能捕獲異步異常示例如下:

try {
  setTimeout(() => {
    name.forEach(() => {});
  },1000)
} catch(error) {
  console.info('try-catch:', error);
}

try-catch 比較適合用在那些可以預見可能出錯的地方。

error 事件捕獲

通常將這個事件綁定在 window 上,但由於歷史原因,使用 DOM 不同級別的綁定方式,會有些差別。測試頁面見這里

DOM0 級方式

也就是使用 window.onerror 指定處理程序,其特點有:

  • 參數有 5 個,對應含義分別為 message — 錯誤信息(字符串)、source — 發生異常的腳本URL(字符串)、lineno — 發生異常的行號(數字)、colno — 發生異常的列號(數字)、error — Error 對象。
  • 函數體內用 return true 可以阻止異常信息出現在控制台。
  • 可以捕獲到異步異常。
  • 不能捕獲到語法異常。
  • 不能捕獲 try-catch 中的異常。
  • 不能捕獲 scriptimginputaudiosourcetrack 標簽元素 src 屬性的加載異常(HTML5 不支持的 frame 標簽不討論)。測試頁面見這里
  • 不能捕獲 link 標簽的加載異常,測試頁面間這里這里

DOM2 級方式

也就是使用 window.addEventListener 指定處理程序,其特點有:

  • 參數對應 1 個,是一個 ErrorEvent 對象,其中包含信息相對 DOM0 級更加豐富。
  • 函數體內用 preventDefault() 方法可以阻止異常信息出現在控制台,但如果是加載資源異常無法阻止。
  • 可以捕獲 scriptimginputaudiosource 標簽元素 src 屬性的加載異常(track 嘗試了一下不行)。由於加載請求不會冒泡,所以需要在事件的捕獲階段監聽才行。但這種方式無法知道 HTTP 的相關狀態。測試頁面見這里
  • 可以捕獲 link 標簽的加載異常,測試頁面間這里這里
  • 可以捕獲異步異常。
  • 不能捕獲到語法異常。
  • 不能捕獲到 try-catch 中的異常。

onerror 事件比較適合捕獲預料之外的異常。

Promise、Async/Await 異常捕獲

Async 函數返回的總是一個 Promise ,如果 Async 函數里面有異常,Promisereject 。所以統一的放到 Promise 里面的 catch 處理會比較方便。其特點:

  • 沒有寫 catchPromise 無法被 onerrortry-catch 捕獲,測試頁面見這里
  • Promisereject 且沒有 reject 處理器的時候,會觸發 unhandledrejection 事件 unhandledrejection
  • 寫了 catch 后,不會觸發 unhandledrejection 事件,所以建議全局增加這個事件監聽。
  • 本地測試驗證的時候,注意跨域的限制,見 issues1issues2

XMLHttpRequest 請求異常捕獲

XMLHttpRequest 目前來說應用非常廣泛,有對應的 error 事件可以進行監聽。在實際中,有可能團隊內已有約定的一套異常狀態碼,可根據實際情況進行對應的處理。這是簡單示例

Fetch 請求異常捕獲

Fetch API 提供了一個獲取資源的接口。它對於使用過 XMLHttpRequest 的人來說會很類似,但這個新的接口提供了更加強大的功能。有下面的一些點需要注意:

  • fetch 方法返回的是一個 Promise ,因此可以使用 catch 進行異常捕獲。
  • 當接收到一個代表錯誤的 HTTP 狀態碼時,fetch 返回的 Promise 不會 reject ,即使響應的 HTTP 狀態碼是 404 或 500。相反,它會 resolve ,但會將 resolve 返回值的 ok 屬性設置為 false ,僅當網絡故障或請求被阻止時,才會 reject 。這是請求為 404 的示例

iframe 異常捕獲

error 事件可以捕獲到一些標簽的 src 加載異常,但 iframe 的情況有些不一樣。在網上找了一些資料,嘗試了下面的一些方法:

  • 使用 window.onerror 方式,無法捕獲,這是測試頁面
  • 使用 window.frames[0].onerror 方式,無法捕獲,這是測試頁面
  • 在標簽上綁定 onerror 事件,沒有觸發,無法捕獲,這是測試頁面
  • 綁定 onload 事件,可以觸發,但無法直接的捕獲,例如一般的網站都設置了 404 頁面,當 src 加載的一個網頁找不到時,就會默認使用 404 網頁,雖然觸發了 onload 事件,但仍然不知道是不是異常。這個時候,可以通過間接的檢測這個顯示 404 頁面的一些信息,來判斷是否異常,比如當發現這個頁面 title 里面有 404 或者 not found 之類的詞匯,那就說明 iframe 加載異常。這個根據實際情況,可以設置其它檢測的標識。這是測試頁面

還有一種思路就是用一個異步請求,讓服務器端判斷一下是否能夠正常的訪問 src 的資源,如果請求返回正常,那就直接動態設置 src 的值,否則就是異常情況,直接上報即可。

跨域

跨域的出現是由於瀏覽器的同源策略,一旦發生,會在控制台出現很明顯的提示。通過查找資料發現,更多的方案是提前解決這個問題,但也有針對特定的情況進行捕獲的方法。下面是相關的資料:

參考資料


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM