摘要:前端開發中的中的中,是一個構造函數,通過它創建一個錯誤對象。是核心對象,表示調用一個時發生的異常。將回調函數包裹一層接下來可以將統一進行處理。中的錯誤捕獲在以前,可以使用來處理捕獲的錯誤。研究結果在這里中的錯誤捕獲的源碼中,在關
本文首發于公眾號:符合預期的CoyPan寫在前面
在前端項目中,由于JavaScript本身是一個弱類型語言,加上瀏覽器環境的復雜性,網絡問題等等,很容易發生錯誤。做好網頁錯誤監控,不斷優化代碼,提高代碼健壯性是一項很重要的工作。本文將從Error開始,講到如何捕獲頁面中的異常。文章較長,細節較多,請耐心觀看。
前端開發中的Error JavaScript中的ErrorJavaScript中,Error是一個構造函數,通過它創建一個錯誤對象。當運行時錯誤產生時,Error的實例對象會被拋出。構造一個Error的語法如下:
// message: 錯誤描述 // fileName: 可選。被創建的Error對象的fileName屬性值。默認是調用Error構造器代碼所在的文件的名字。 // lineNumber: 可選。被創建的Error對象的lineNumber屬性值。默認是調用Error構造器代碼所在的文件的行號。 new Error([message[, fileName[, lineNumber]]])
Error有兩個標準屬性:
Error.prototype.name :錯誤的名字
Error.prototype.message:錯誤的描述
例如,在chrome控制臺中輸入以下代碼:
var a = new Error("錯誤測試"); console.log(a); // Error: 錯誤測試 // at:1:9 console.log(a.name); // Error console.log(a.message); // 錯誤測試
Error只有一個標準方法:
Error.prototype.toString:返回表示一個表示錯誤的字符串。
接上面的代碼:
a.toString(); // "Error: 錯誤測試"
各個瀏覽器廠商對于Error都有自己的實現。比如下面這些屬性:
Error.prototype.fileName:產生錯誤的文件名。
Error.prototype.lineNumber:產生錯誤的行號。
Error.prototype.columnNumber:產生錯誤的列號。
Error.prototype.stack:堆棧信息。這個比較常用。
這些屬性均不是標準屬性,在生產環境中謹慎使用。不過現代瀏覽器差不多都支持了。
除了通用的Error構造函數外,JavaScript還有7個其他類型的錯誤構造函數。
InternalError: 創建一個代表Javascript引擎內部錯誤的異常拋出的實例。 如:?"遞歸太多"。非ECMAScript標準。
RangeError: 數值變量或參數超出其有效范圍。例子:var a = new Array(-1);
EvalError: 與eval()相關的錯誤。eval()本身沒有正確執行。
ReferenceError: 引用錯誤。 例子:console.log(b);
SyntaxError: 語法錯誤。例子:var a = ;
TypeError: 變量或參數不屬于有效范圍。例子:[1,2].split(".")
URIError: 給?encodeURI或?decodeURl()傳遞的參數無效。例子:decodeURI("%2")
當JavaScript運行過程中出錯時,會拋出上8種(上述7種加上通用錯誤類型)錯誤中的其中一種錯誤。錯誤類型可以通過error.name拿到。
你也可以基于Error構造自己的錯誤類型,這里就不展開了。
其他錯誤上面介紹的都是JavaScript本身運行時會發生的錯誤。頁面中還會有其他的異常,比如錯誤地操作了DOM。
DOMException是W3C DOM核心對象,表示調用一個Web Api時發生的異常。什么是Web Api呢?最常見的就是DOM元素的一系列方法,其他還有XMLHttpRequest、Fetch等等等等,這里就不一一說明了。直接看下面一個操作DOM的例子:
var node = document.querySelector("#app"); var refnode = node.nextSibling; var newnode = document.createElement("div"); node.insertBefore(newnode, refnode); // 報錯:Uncaught DOMException: Failed to execute "insertBefore" on "Node": The node before which the new node is to be inserted is not a child of this node.
單從JS代碼邏輯層面來看,沒有問題。但是代碼的操作不符合DOM的規則。
DOMException構造函數的語法如下:
// message: 可選,錯誤描述。 // name: 可選,錯誤名稱。常量,具體值可以在這里找到:https://developer.mozilla.org/zh-CN/docs/Web/API/DOMException new DOMException([message[, name]]);
DOMException有以下三個屬性:
DOMException.code:錯誤編號。
DOMException.message:錯誤描述。
DOMException.name:錯誤名稱。
以上面那段錯誤代碼為例,其拋出的DOMException各屬性的值為:
code: 8 message: "Failed to execute "insertBefore" on "Node": The node before which the new node is to be inserted is not a child of this node." name: "NotFoundError"
在Promise中,如果Promise被reject了,就會拋出異常:PromiseRejectionEvent。注意,下面兩種情況都會導致Promise被reject:
業務代碼本身調用了Promise.reject。
Promise中的代碼出錯。
PromiseRejectionEvent的構造函數目前在瀏覽器中大多都不兼容,這里就不說了。
PromiseRejectionEvent的屬性有兩個:
PromiseRejectionEvent.promise:被reject的Promise。
PromiseRejectionEvent.reason:Promise被reject的原因。會傳遞給reject。Promsie的catch中的參數。
由于網絡,安全等原因,網頁加載資源失敗,請求接口出錯等,也是一種常見的錯誤。
關于錯誤的小結一個網頁在運行過程中,可能發生四種錯誤:
JavaScript在運行過程,語言自身拋出的異常。
JavaScript在運行過程中,調用Web Api時發生異常。
Promise中的拒絕。
網頁加載資源,調用接口時發生異常。
我認為,對于前兩種錯誤,我們在平時的開發過程中,不用特別去區分,可以統一成:【代碼出錯】。
捕獲錯誤網頁發生錯誤,開發者如何捕獲這些錯誤呢 ? 常見的有以下方法。
try...catch...try...catch…大家都不陌生了。一般用來在具體的代碼邏輯中捕獲錯誤。
try { throw new Error("oops"); } catch (ex) { console.log("error", ex.message); // error oops }
當try-block中的代碼發生異常時,可以在catck-block中將異常接住,瀏覽器便不會拋出錯誤。但是,這種方式并不能捕獲異步代碼中的錯誤,如:
try { setTimeout(function(){ throw new Error("lala"); },0); } catch(e) { console.log("error", e.message); }
這個時候,瀏覽器依然會拋出錯誤:Uncaught Error: lala。
試想以下,如果我們將所有的代碼合理的劃分,然后都用try catch包起來,是不是就可以捕獲到所有的錯誤了呢?可以通過編譯工具來實現這個功能。不過,try catch是比較耗費性能的。
window.onerrorwindow.onerror = function(message, source, lineno, colno, error) { ... }
函數參數:
message:錯誤信息(字符串)
source:發生錯誤的腳本URL(字符串)
lineno:發生錯誤的行號(數字)
colno:發生錯誤的列號(數字)
error:Error對象(對象)
注意,如果這個函數返回true,那么將會阻止執行瀏覽器默認的錯誤處理函數。
window.addEventListener("error")window.addEventListener("error", function(event) { ... })
我們調用Object.prototype.toString.call(event),返回的是[object ErrorEvent]。可以看到event是ErrorEvent對象的實例。ErrorEvent是事件對象在腳本發生錯誤時產生,從Event繼承而來。由于是事件,自然可以拿到target屬性。ErrorEvent還包括了錯誤發生時的信息。
ErrorEvent.prototype.message: 字符串,包含了所發生錯誤的描述信息。
ErrorEvent.prototype.filename: 字符串,包含了發生錯誤的腳本文件的文件名。
ErrorEvent.prototype.lineno: 數字,包含了錯誤發生時所在的行號。
ErrorEvent.prototype.colno: 數字,包含了錯誤發生時所在的列號。
ErrorEvent.prototype.error: 發生錯誤時所拋出的 Error 對象。
注意,這里的ErrorEvent.prototype.error對應的Error對象,就是上文提到的Error, InternalError,RangeError,EvalError,ReferenceError,SyntaxError,TypeError,URIError,DOMException中的一種。
window.addEventListener("unhandledrejection")window.addEventListener("unhandledrejection", function (event) { ... });
在使用Promise的時候,如果沒有聲明catch代碼塊,Promise的異常會被拋出。只能通過這個方法或者window.onunhandledrejection才能捕獲到該異常。
event就是上文提到的PromiseRejectionEvent。我們只需要關注其reason就行。
window.onerror 和 window.addEventListener("error")的區別首先是事件監聽器和事件處理器的區別。監聽器只能聲明一次,后續的聲明會覆蓋之前的聲明。而事件處理器則可以綁定多個回調函數。
資源( 或
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/100603.html
摘要:前端異常監控如果是移除的流程,那么編程就一定是將放進去的流程。過濾掉運行時錯誤上報加載錯誤事件捕獲異常最新的規范中定義了事件用于全局捕獲對象沒有處理器時異常情況。 前端異常監控 如果debug是移除bug的流程,那么編程就一定是將bug放進去的流程。如果沒有用戶反饋問題,那就代表我們的產品棒棒噠,對不對? 主要內容 Web規范中相關前端異常 異常按照捕獲方式分類 異常的捕獲方式 日志...
摘要:錯誤上報機制發送數據因為請求本身也有可能會發生異常,而且有可能會引發跨域問題,一般情況下更推薦使用動態創建標簽的形式進行上報。 js錯誤捕獲 js錯誤的實質,也是發出一個事件,處理他 error實例對象 對象屬性 message:錯誤提示信息 name:錯誤名稱(非標準屬性)宿主環境賦予 stack:錯誤的堆棧(非標準屬性)宿主環境賦予 對象類型(7種) Synt...
摘要:我打算分成前端魔法堂異常不僅僅是和前端魔法堂調用棧,異常實例中的寶藏兩篇分別敘述內置自定義異常類,捕獲運行時異常語法異常網絡請求異常事件,什么是調用棧和如何獲取調用棧的相關信息。 前言 ?編程時我們往往拿到的是業務流程正確的業務說明文檔或規范,但實際開發中卻布滿荊棘和例外情況,而這些例外中包含業務用例的例外,也包含技術上的例外。對于業務用例的例外我們別無它法,必須要求實施人員與用戶共同...
摘要:回過頭來發現,我們的項目,雖然在服務端層面做好了日志和性能統計,但在前端對異常的監控和性能的統計。對于前端的性能與異常上報的可行性探索是有必要的。這是我們頁面加載性能優化需求中主要上報的相關信息。 概述 對于后臺開發來說,記錄日志是一種非常常見的開發習慣,通常我們會使用try...catch代碼塊來主動捕獲錯誤、對于每次接口調用,也會記錄下每次接口調用的時間消耗,以便我們監控服務器接口...
閱讀 851·2021-11-15 17:58
閱讀 3652·2021-11-12 10:36
閱讀 3788·2021-09-22 16:06
閱讀 965·2021-09-10 10:50
閱讀 1332·2019-08-30 11:19
閱讀 3315·2019-08-29 16:26
閱讀 937·2019-08-29 10:55
閱讀 3347·2019-08-26 13:48