是指用戶在使用應用時,沒法獲得預期的結果。不一樣的異常帶來的後果程度不一樣,輕則引發用戶使用不悅,重則致使產品沒法使用,從而使用戶喪失對產品的承認。css
異常 | 頻率 |
---|---|
JavaScript異常(語法錯誤、代碼錯誤) | 常常 |
靜態資源加載異常(img、js、css) | 偶爾 |
Ajax 請求異常 | 偶爾 |
promise異常 | 較少 |
iframe 異常 | 較少 |
try-catch 只能捕獲同步運行錯誤,對語法和異步錯誤卻捕獲不到。html
一、同步運行錯誤前端
try { kill; } catch(err) { console.error('try: ', err); }
結果:try: ReferenceError: kill is not defined
vue
二、沒法捕獲語法錯誤react
try { let name = '1; } catch(err) { console.error('try: ', err); }
結果:Unterminated string constant
git
編譯器可以阻止運行語法錯誤。github
三、沒法捕獲異步錯誤promise
try { setTimeout(() => { undefined.map(v => v); }, 1000); } catch(err) { console.error('try: ', err); }
結果:Uncaught TypeError: Cannot read property 'map' of undefined
瀏覽器
當JavaScript運行時錯誤(包括語法錯誤)發生時,window會觸發一個ErrorEvent接口的error事件,並執行window.onerror()。若該函數返回true,則阻止執行默認事件處理函數。服務器
一、同步運行錯誤
/** * @param {String} message 錯誤信息 * @param {String} source 出錯文件 * @param {Number} lineno 行號 * @param {Number} colno 列號 * @param {Object} error error對象 */ window.onerror = (message, source, lineno, colno, error) => { console.error('捕獲異常:', message, source, lineno, colno, error); return true; }; kill;
結果:捕獲異常: Uncaught ReferenceError: kill is not defined
二、沒法捕獲語法錯誤
/** * @param {String} message 錯誤信息 * @param {String} source 出錯文件 * @param {Number} lineno 行號 * @param {Number} colno 列號 * @param {Object} error error對象 */ window.onerror = (message, source, lineno, colno, error) => { console.error('捕獲異常:', message, source, lineno, colno, error); return true; }; let name = '1;
結果:Unterminated string constant
編譯器可以阻止運行語法錯誤。
三、異步錯誤
/** * @param {String} message 錯誤信息 * @param {String} source 出錯文件 * @param {Number} lineno 行號 * @param {Number} colno 列號 * @param {Object} error error對象 */ window.onerror = (message, source, lineno, colno, error) => { console.error('捕獲異常:', message, source, lineno, colno, error); return true; }; setTimeout(() => { undefined.map(v => v); }, 1000);
結果:捕獲異常: Uncaught TypeError: Cannot read property 'map' of undefined
當一項資源(如<img>
或<script>
)加載失敗,加載資源的元素會觸發一個Event接口的error事件,並執行該元素上的onerror()處理函數。這些error事件不會向上冒泡到window,不過(至少在Firefox中)能被單一的window.addEventListener捕獲。
<script> window.addEventListener('error', (err) => { console.error('捕獲異常:', err); }, true); </script> <img src="./test.jpg" />
結果:捕獲異常:Event {isTrusted: true, type: "error", target: img, currentTarget: Window, eventPhase: 1, …}
當Promise 被 reject 且沒有 reject 處理器的時候,會觸發 unhandledrejection 事件;這可能發生在 window 下,但也可能發生在 Worker 中。 這對於調試回退錯誤處理很是有用。
window.addEventListener("unhandledrejection", (err) => { err.preventDefault(); console.error('捕獲異常:', err); }); Promise.reject('promise');
結果:捕獲異常:PromiseRejectionEvent {isTrusted: true, promise: Promise, reason: "promise", type: "unhandledrejection", target: Window, …}
Vue.config.errorHandler = (err, vm, info) => { console.error('捕獲異常:', err, vm, info); }
React 16,提供了一個內置函數componentDidCatch
,使用它能夠很是簡單的獲取到React
下的錯誤信息。
componentDidCatch(error, info) { console.error('捕獲異常:', error, info); }
可是,推薦ErrorBoundary
用戶界面中的JavaScript錯誤不該破壞整個應用程序。爲了爲React用戶解決此問題,React 16引入了「錯誤邊界」的新概念。
新建ErrorBoundary.jsx
組件:
import React from 'react'; import { Result, Button } from 'antd'; class ErrorBoundary extends React.Component { constructor(props) { super(props); this.state = { hasError: false, info: '' }; } static getDerivedStateFromError(error) { return { hasError: true }; } componentDidCatch(error, info) { this.setState({ info: error + '' }); } render() { if (this.state.hasError) { // 你能夠渲染任何自定義的降級 UI return ( <Result status="500" title="500" subTitle={this.state.info} extra={<Button type="primary">Report feedback</Button>} /> ); } return this.props.children; } } export default ErrorBoundary;
使用:
<ErrorBoundary> <App /> </ErrorBoundary>
注意
錯誤邊界不會捕獲如下方面的錯誤:
因爲瀏覽器設置的「同源策略」,沒法很是優雅的處理iframe異常,除了基本屬性(例如其寬度和高度)以外,沒法從iFrame得到不少信息。
<script> document.getElementById("myiframe").onload = () => { const self = document.getElementById('myiframe'); try { (self.contentWindow || self.contentDocument).location.href; } catch(err) { console.log('捕獲異常:' + err); } }; </script> <iframe id="myiframe" src="https://nibuzhidao.com" frameBorder="0" />
業界很是優秀的一款監控異常的產品,做者也是用的這款,文檔齊全。
一、Ajax發送數據
二、動態建立img標籤
若是異常數據量大,致使服務器負載高,調整發送頻率(能夠考慮把異常信息存儲在客戶端,設定時間閥值,進行上報)或設置採集率(採集率應該經過實際狀況來設定,隨機數,或者某些用戶特徵都是不錯的選擇)。