優雅處理前端異常的幾種方式推薦

一、為什麼要處理異常?

1、未雨綢繆,盡早發現問題

2、讓異常變得可控,避免影響呈現結果

3、增強用戶體驗

4、完善的前端方案

二、需要處理哪些異常?

1、JavaScript 語法錯誤、代碼異常

2、異步請求異常

3、靜態資源加載異常

4、Promise 異常

5、跨域

6、崩潰與渲染異常

三、處理異常的方式有哪些?

1、try-catch

我們可以使用 try-catch 對同步代碼運行異常進行捕獲。

例如:

try {
  let name = 'leo';
  console.log(age);
} catch(e) {
  console.log('捕獲到異常:',e);
}
 
// 捕獲到異常: ReferenceError: age is not defined

try-catch 無法捕獲語法錯誤和異步錯誤。 

例如:

try {
  let name = 'leo;   // 缺少一個單引號,屬於語法錯誤,在開發階段便提示出來
  console.log(age);
} catch(e) {
  console.log('捕獲到異常:',e);
}
// Uncaught SyntaxError: Invalid or unexpected token
try {
  setTimeout(() => {
    undefined.map(v => v*2);
  }, 1000)
} catch(e) {
  console.log('捕獲到異常:',e);
}
 

由於 setTimeout 屬於異步,try-catch 並沒有捕獲到,查看日志

// Uncaught TypeError: Cannot read property 'map' of undefined

2、window.onerror

我們可以使用 window.onerror 對 JavaScript 運行錯誤時進行捕獲。

window.onerror = function(message, source, lineNo, colNo, error) {
  console.log('捕獲到異常:',{message, source, lineNo, colNo, error});
}
 
/**
* message   錯誤信息
* source    出錯文件
* lineNo    行號
* colNo     列號
* error     Error對象(對象)
*/

同步運行錯誤

window.onerror = function(message, source, lineNo, colNo, error) {
  console.log('捕獲到異常:',{message, source, lineNo, colNo, error});
}
leo;

捕獲到異常 

語法錯誤

window.onerror = function(message, source, lineNo, colNo, error) {
  console.log('捕獲到異常:',{message, source, lineNo, colNo, error});
}
let name = 'leo

與 try-catch 一樣,無法捕獲語法錯誤。 

異步運行錯誤

window.onerror = function(message, source, lineNo, colNo, error) {
  console.log('捕獲到異常:',{message, source, lineNo, colNo, error});
}
setTimeout(() => {
  leo;
},1000)

捕獲到異常

window.onerror 在捕獲到錯誤時,會向上拋出,如上例,控制臺會出現

我們可以在函數裡面使用 return true,使異常不向上拋出,此時控制臺不會顯示如上錯誤信息

window.onerror = function(message, source, lineNo, colNo, error) {
  console.log('捕獲到異常:',{message, source, lineNo, colNo, error});
  return true;   // 異常不向上拋出
}
setTimeout(() => {
  leo;
},1000)

window.onerror 最好寫在所有 JavaScript 腳本前面,否則有可能捕獲不到異常;

window.onerror 無法捕獲語法異常、靜態資源異常、接口請求異常;

window.onerror 主要用來捕獲意料之外的異常,而 try-catch 則是用來捕獲可預見的異常。 

3、window.addEventListener

我們可以使用 window.addEventListener 對靜態資源加載異常與接口請求異常進行捕獲。

<scritp>
window.addEventListener('error', (error) => {
    console.log('捕獲到異常:', error);
}, true)
</script>
<img src="../../assets/test.png">

捕獲到異常

當一項資源(如圖片或腳本)加載失敗,加載資源的元素會觸發一個 Event 接口的 error 事件,並執行該元素上的 onerror 處理函數。

由於網絡請求異常不會事件冒泡,因此必須在捕獲階段將其捕捉到才行,但是這種方式雖然可以捕捉到網絡請求的異常,但是無法判斷狀態碼是 404 還是其他比如 500 等等,所以還需要配合服務端日志才進行排查分析才可以。

不同的瀏覽器返回的 error 對象可能不一樣,需要做兼容;

避免 addEventListener 重復監聽。 

4、Promise catch

我們可以使用 Promise 中的 catch 捕獲異步錯誤。

new Promise((resolve,reject) => {
  reject("執行失敗!")
}).catch(error => {
  console.log("捕獲到異常:",error)
})

捕獲到異常 

有時候我們在寫 Promise 可能會漏掉 catch,所以建議在全局增加一個對 unhandledrejection 的監聽,用來全局監聽 Uncaught Promise Error。

window.addEventListener("unhandledrejection", function(e){
  e.preventDefault()
  console.log('捕獲到異常:', e);
});
new Promise((resolve,reject) => {
  reject("執行失敗!")
})

捕獲到異常

添加  event.preventDefault(); 可以去掉控制臺的異常顯示信息。

5、vue errorHandler

我們可以使用 errorHandler 對 vue 組件中所拋錯誤的捕捉與處理。

Vue.config.errorHandler = (err, vm, info) => {
  console.error(err);
  console.error(vm);
  console.error(info);
}
 
// 某個組件的 mounted
const error = new Error('test error');
error.code = -1;
throw error;

捕獲到異常

6、 react 異常捕獲

React 16 提供瞭一個內置函數 componentDidCatch,使用它可以非常簡單的獲取到 react 下的錯誤信息。

componentDidCatch(error, info) {
  console.log(error, info);
}

除此之外,也可以使用錯誤邊界 error boundary,此處不展開。

7、跨域

資源跨域可以為 script 標簽添加 crossOrigin 屬性。

<script src="http://localhost:3000/main.js" crossorigin></script>

也可以動態添加 JavaScript 腳本

const script = document.createElement('script');
script.crossOrigin = 'anonymous';
script.src = url;
document.body.appendChild(script);

四、總結

處理異常方式 說明
try-catch 可預見、可疑區域
window.onerror 全局捕獲 JavaScript 異常
window.addEventListener 全局捕獲靜態資源異常
Promise catch 捕獲 Promise 異常,也可使用 unhandledrejection 進行全局捕獲
vue errorHandler 捕獲 vue 異常
react 異常捕獲 捕獲 react 異常
crossOrigin 解決 JavaScript 腳本跨域

到此這篇關於優雅處理前端異常的幾種方式文章就介紹到這瞭,更多相關優雅處理前端異常內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

參考:如何優雅處理前端異常? – Jartto's blog 

推薦閱讀: