本次寫做來源於一次面試,前端架構師崗位,最後面試官臨時給我掏出了一道比較少見的面試題 ,終究斬獲offer ,雖然這道題並不難,可是考察的東西挺有趣,加上近期有看到前端防護性編程、優雅處理前端錯誤的文章,因而想起來把這道題寫了下來。html
這是一個關於前端錯誤處理的題目,由淺入深前端
本題答案: xxxx未定義,致命錯誤,以前無錯誤捕獲處理機制,頁面沒有跳轉到百度react
第二個版本:webpack
這裏仍是比較簡單,由於try裏面纔會捕獲錯誤,一旦拋出錯誤就會被全局捕獲錯誤的函數捕獲 最終輸出順序: try 拋出錯誤 全局捕獲到錯誤git
加入函數調用版本,問最終打印臺輸出什麼 github
調用test,執行test,執行完了try同步代碼後,執行拋出Error,結束test的函數的調用(只要函數內部拋出錯誤,就會結束這個函數的調用而且出棧),全局捕獲到的錯誤,仍是‘拋出錯誤’這個咱們本身定義的錯誤內容,console.log(a)並無被執行到 web
變異版本 面試
這裏主要考察的是函數的拋出錯誤配合finally的執行,咱們一直認爲,只要函數內部拋出錯誤,就會結束這個函數調用,立馬出棧。因此return和throw new Error不能在一塊兒用,可是finally卻仍是依然會執行。finally,顧名思義,最後都會執行ajax
> finally 語句在 try 和 catch 以後不管有無異常都會執行。數據庫
加入webpack工程化構建的變異版本,選中此html爲模板,問, 若是其餘經過webpack構建的文件發生了致命錯誤,例如由於作了tree sharking,沒有兼容低版本瀏覽器,此時能夠捕獲到全局錯誤嗎
答案是不能夠捕獲到,由於通過webpack打包後,代碼會變成
若是此時其餘模塊發生了致命錯誤,例如const這種代碼跑在IE6中,那麼就會直接致命錯誤,阻斷瀏覽器解析代碼,頁面掛掉。js引擎也不會去解析下面的代碼~ 尚未運行到window.onerror這裏就掛了
上面只是一個比較簡單的面試題,考察錯誤處理能力,後面是結合React的錯誤邊界,資源請求錯誤,ajax請求錯誤等的處理來口述,這裏可能須要你平時對這些東西有比較多瞭解和實踐才能hold住
window.onerror與window.addEventListener('error')捕獲js運行時錯誤
使用window.onerror和window.addEventListener('error')都能捕獲,可是window.onerror含有詳細的error堆棧信息,存在error.stack中,因此咱們選擇使用onerror的方式對js運行時錯誤進行捕獲。
資源加載錯誤使用addEventListener去監聽error事件捕獲
實現原理:當一項資源(如<img>或<script>)加載失敗,加載資源的元素會觸發一個Event接口的error事件,並執行該元素上的onerror()處理函數。
這些error事件不會向上冒泡到window,不過能被window.addEventListener在捕獲階段捕獲。
但這裏須要注意,因爲上面提到了addEventListener也可以捕獲js錯誤,所以須要過濾避免重複捕獲,判斷爲資源錯誤的時候才進行處理。
僞代碼
window.addEventListener('error', (e) => {
這樣就能夠捕獲到任意的圖片等資源加載錯誤的信息,可是捕獲後依舊會有爆紅提示,我猜測這種資源請求錯誤是很是重要的,必須爆出來?
Error Boundaries(錯誤邊界)配合webpack+系統的onerror錯誤捕獲
有人說使用 create-react-app 建立的項目,在開發環境,就算使用了 componentDidCatch 或者 getDerivedStateFromError,錯誤依然會被拋出,在 build 後,錯誤將會捕獲,不會致使整個項目卸載(這點我不肯定,由於我都是本身配腳手架的)
根據官方文檔所說,在 react 16 之後,任何未被錯誤邊界捕獲的錯誤將會致使整個 React 組件樹被卸載。因此咱們在開發項目時,須要去捕獲錯誤邊界的錯誤,並提供一個備用UI,那麼被錯誤邊界捕獲的錯誤,還會冒泡到window中嗎
多說無益,咱們先實踐
咱們先定義一個錯誤邊界,而後html模板文件中,依舊有咱們的那段代碼
此時將錯誤邊界組件包裹APP根組件~
運行代碼,一切正常
此時React根組件的componentDidmount生命週期函數拋出錯誤
拋出錯誤後,被錯誤邊界捕獲
說明這種錯誤被React錯誤邊界捕獲後,就不會再被onerror函數捕獲,那麼window.addEventListenr呢? 嘗試一下。
一樣,也沒有被捕獲,通過測試,dom2形式監聽error事件,不管第三個參數是false仍是true,只要被錯誤邊界捕獲後,都不會再被捕獲。
接下來是語法錯誤
若是是同步的語法錯誤,在try catch中就能夠被捕獲,不會冒泡到window.onerror事件中
異步語法錯誤
最終被全局到error回調函數捕獲,可是你們很奇怪,這裏爲何捕獲了,還會爆出錯誤?咱們以前是不會的。
這裏要說明一點,若是是人爲拋出錯誤 throw new Error,error函數是能夠捕獲的。可是一旦是語法錯誤,那麼須要在error函數中return true,這樣異常纔不會往上繼續拋出。
當咱們打開return true 時候
全局錯誤捕獲,而且控制檯不會出現未捕獲的錯誤了~
細心的朋友會發現,控制檯一直有一個報錯,沒錯,這是一個靜態資源的請求,img標籤。
項目中有一段這個代碼
<img src="ssss" alt=""/>
最終返回響應是:
**這裏能夠肯定,靜態資源請求錯誤,不會冒泡到window.error事件中,只能夠經過上面的dom2形式經過在捕獲階段捕獲到這個錯誤
**
window.addEventListener('error', (e) => {
dom2形式捕獲到了這個請求資源錯誤,並且同時觸發了這個標籤的onerror事件
<img src="ssss" alt="" onError={(e)=>{console.log('圖片加載失敗',e)}}/>
一些圖片的處理,能夠相似這樣,當請求的靜態資源出現錯誤時候,能夠更換請求地址
,不會致使碎圖
Promise的捕獲,對於頻繁調用的函數,確定是須要封裝成promise風格的,統一處理錯誤,統一接口捕獲一次就能夠了,由於onerror函數並不能捕獲promise錯誤,這裏我就不演示了
> 網絡請求錯誤也是不會被error函數捕獲的,可是咱們能夠封裝成promise風格,統一本身catch錯誤處理
因爲async await函數和promise可能比較多,項目中,爲了防止沒有捕獲的promise出現,咱們可使用
這樣就能夠經過unhandledrejection這個事件捕獲到沒有處理錯誤的promise
對於錯誤上報,通常是採用不會跨域的請求,例如img標籤、audio標籤等靜態資源get請求後面將error信息拼接,後臺截取查詢字符串存入數據庫和緩存中提供記錄和查詢能力
new Image().src = `${url}?err=${error}`;
這樣後端就能夠接受到異常錯誤信息了
好久以前看過有用Performance和beforeunload, servece worker去處理極端狀況的,你們有興趣也能夠去看看,我這裏就不作過多的介紹,前者使用也比較簡單,後者並不太適用每一個人。
因爲如今的錯誤監控、上報已經造成了一套完整的商業鏈,這方面並非個人強項,若是寫得不對的地方,歡迎指出,架構師崗位面試,更考察你對項目總體把控能力,最後出現這個題目,我以爲也正常
本開源項目gitHub地址(React和webpack,練手適合):
https://github.com/JinJieTan/react-webpack
若是感受寫得不錯,能夠幫忙點個-在看
但願每一個人都會像老許同樣
有人問你,你要老婆/老公不要?
要的話,就給你送來