核心要點
window.onerror
是一個瀏覽器事件,在拋出未捕獲的 JavaScript 錯誤時觸發,提供了一種簡單的記錄客戶端錯誤並將其報告到服務器的方法。所有現代瀏覽器都支持此事件,但實現細節有所不同。 window.onerror
的 Error 對像對於調試非常有價值,因為它包含錯誤堆棧跟踪,該跟踪提供了程序出錯時每個幀的源位置。但是,stack 屬性是非標準的,其在不同瀏覽器中的實現方式也不同。 window.onerror
廣泛支持,但並非所有瀏覽器都傳遞 Error 對象,這意味著它們無法檢索 stack 跟踪屬性。可以通過將代碼包裝在 try/catch 塊中來解決此限制,以捕獲錯誤及其 stack 屬性。 本文與 Sentry 合作創作。感謝您支持使 SitePoint 成為可能的合作夥伴。
window.onerror
是一個特殊的瀏覽器事件,每當拋出未捕獲的 JavaScript 錯誤時就會觸發。它是記錄客戶端錯誤並將其報告到服務器的最簡單方法之一。這也是 Sentry 的客戶端 JavaScript 集成 (raven-js) 工作的主要機制之一。
通過將函數分配給 window.onerror
來監聽 onerror
事件:
window.onerror = function (msg, url, lineNo, columnNo, error) { // ... 处理错误 ... return false; }
拋出錯誤時,以下參數將傳遞給函數:
msg
– 與錯誤關聯的消息,例如“Uncaught ReferenceError: foo is not defined”url
– 與錯誤關聯的腳本或文檔的 URL,例如“/dist/app.js”lineNo
– 行號(如果可用)columnNo
– 列號(如果可用)error
– 與此錯誤關聯的 Error 對象(如果可用)前四個參數告訴您錯誤發生在哪個腳本、行和列中。最後一個參數,Error 對象,也許是最有價值的。讓我們了解原因。
Error 對象和 error.stack
乍一看,Error 對象並不特別。它包含 3 個標準化屬性:message、fileName 和 lineNumber。這些冗餘值已通過 window.onerror
提供給您。
有價值的部分是一個非標準屬性:Error.prototype.stack
。此 stack 屬性告訴您程序出錯時每個程序幀的源位置。錯誤堆棧跟踪可能是調試的關鍵部分。儘管是非標準的,但此屬性在每個現代瀏覽器中都可用。
以下是 Chrome 46 中 Error 對象的 stack 屬性示例:
window.onerror = function (msg, url, lineNo, columnNo, error) { // ... 处理错误 ... return false; }
難以閱讀,對吧? stack 屬性實際上只是一個未格式化的字符串。
以下是格式化後的樣子:
<code>"Error: foobar\n at new bar (<anonymous>:241:11)\n at foo (<anonymous>:245:5)\n at <anonymous>:250:5\n at <anonymous>:251:3\n at <anonymous>:267:4\n at callFunction (<anonymous>:229:33)\n at <anonymous>:239:23\n at <anonymous>:240:3\n at Object.InjectedScript._evaluateOn (<anonymous>:875:140)\n at Object.InjectedScript._evaluateAndWrap (<anonymous>:808:34)" </anonymous></anonymous></anonymous></anonymous></anonymous></anonymous></anonymous></anonymous></anonymous></anonymous></code>
格式化後,很容易看出 stack 屬性如何在幫助調試錯誤方面至關重要。
只有一個問題:stack 屬性是非標準的,其在不同瀏覽器中的實現方式也不同。例如,以下是 Internet Explorer 11 中的相同堆棧跟踪:
<code>Error: foobar at new bar (<anonymous>:241:11) at foo (<anonymous>:245:5) at callFunction (<anonymous>:229:33) at Object.InjectedScript._evaluateOn (<anonymous>:875:140) at Object.InjectedScript._evaluateAndWrap (<anonymous>:808:34) </anonymous></anonymous></anonymous></anonymous></anonymous></code>
每個幀的格式不僅不同,幀的細節也更少。例如,Chrome 識別已使用 new 關鍵字,並且對 eval 調用有更深入的了解。這只是 IE 11 與 Chrome 的比較——其他瀏覽器也類似地具有不同的格式和細節。
幸運的是,有一些工具可以規範化 stack 屬性,使其在不同瀏覽器中保持一致。例如,raven-js 使用 TraceKit 來規範化錯誤字符串。還有 stacktrace.js 和其他一些項目。
瀏覽器兼容性
window.onerror
在瀏覽器中已經存在一段時間了——您可以在 IE6 和 Firefox 2 等舊版瀏覽器中找到它。
問題是每個瀏覽器都以不同的方式實現 window.onerror
,尤其是在發送到 onerror 偵聽器的參數數量和這些參數的結構方面。
以下是大多數瀏覽器中傳遞給 onerror 的參數的表格:
浏览器 | Message | URL | lineNo | colNo | errorObj |
---|---|---|---|---|---|
Firefox | ✓ | ✓ | ✓ | ✓ | ✓ |
Chrome | ✓ | ✓ | ✓ | ✓ | ✓ |
Edge | ✓ | ✓ | ✓ | ✓ | ✓ |
IE 11 | ✓ | ✓ | ✓ | ✓ | ✓ |
IE 10 | ✓ | ✓ | ✓ | ✓ | |
IE 9, 8 | ✓ | ✓ | ✓ | ||
Safari 10 及以上 | ✓ | ✓ | ✓ | ✓ | ✓ |
Safari 9 | ✓ | ✓ | ✓ | ✓ | |
Android 浏览器 4.4 | ✓ | ✓ | ✓ | ✓ |
Internet Explorer 8、9 和 10 對 onerror
的支持有限,這可能並不令人意外。但您可能會驚訝地發現,Safari 直到 Safari 10(於 2016 年發布)才添加對 error 對象的支持。此外,仍然使用庫存 Android 瀏覽器(現已替換為 Chrome Mobile)的舊版移動設備仍然存在,並且不會傳遞 error 對象。
如果沒有 error 對象,就沒有 stack 跟踪屬性。這意味著這些瀏覽器無法從 onerror
捕獲的錯誤中檢索有價值的堆棧信息。
使用 try/catch 為 window.onerror 提供 polyfill
但是有一個解決方法——您可以將應用程序中的代碼包裝在 try/catch 塊中,並自行捕獲錯誤。此 error 對象將在每個現代瀏覽器中包含我們夢寐以求的 stack 屬性。
考慮以下輔助方法 invoke
,它使用一系列參數在對像上調用函數:
window.onerror = function (msg, url, lineNo, columnNo, error) { // ... 处理错误 ... return false; }
以下是再次調用的 invoke
,這次包裝在 try/catch 中,以便捕獲任何拋出的錯誤:
<code>"Error: foobar\n at new bar (<anonymous>:241:11)\n at foo (<anonymous>:245:5)\n at <anonymous>:250:5\n at <anonymous>:251:3\n at <anonymous>:267:4\n at callFunction (<anonymous>:229:33)\n at <anonymous>:239:23\n at <anonymous>:240:3\n at Object.InjectedScript._evaluateOn (<anonymous>:875:140)\n at Object.InjectedScript._evaluateAndWrap (<anonymous>:808:34)" </anonymous></anonymous></anonymous></anonymous></anonymous></anonymous></anonymous></anonymous></anonymous></anonymous></code>
當然,在任何地方手動執行此操作都非常麻煩。您可以通過創建通用的包裝器實用程序函數來簡化它:
<code>Error: foobar at new bar (<anonymous>:241:11) at foo (<anonymous>:245:5) at callFunction (<anonymous>:229:33) at Object.InjectedScript._evaluateOn (<anonymous>:875:140) at Object.InjectedScript._evaluateAndWrap (<anonymous>:808:34) </anonymous></anonymous></anonymous></anonymous></anonymous></code>
因為 JavaScript 是單線程的,所以您不需要在任何地方都使用包裝器——只需在每個新堆棧的開頭即可。
這意味著您需要包裝函數聲明:
$(document).ready
中)addEventListener
或 $.fn.click
)setTimeout
或 requestAnimationFrame
)例如:
<code>Error: foobar at bar (Unknown script code:2:5) at foo (Unknown script code:6:5) at Anonymous function (Unknown script code:11:5) at Anonymous function (Unknown script code:10:2) at Anonymous function (Unknown script code:1:73)</code>
如果這看起來像很多工作,別擔心!大多數錯誤報告庫都有增強內置函數(如 addEventListener
和 setTimeout
)的機制,因此您不必每次都自己調用包裝實用程序。是的,raven-js 也這樣做。
將錯誤傳輸到服務器
好的,您已經完成了您的工作——您已經插入了 window.onerror
,並且您還將函數包裝在 try/catch 塊中,以便捕獲盡可能多的錯誤信息。
只剩最後一步:將錯誤信息傳輸到服務器。為了使這能夠工作,您需要設置某種報告 Web 服務,該服務將通過 HTTP 接收您的錯誤數據,將其記錄到文件和/或存儲到數據庫中。
如果此 Web 服務與您的 Web 應用程序位於同一域,則只需使用 XMLHttpRequest。在下面的示例中,我們使用 jQuery 的 AJAX 函數將數據傳輸到我們的服務器:
function invoke(obj, method, args) { return obj[method].apply(this, args); } invoke(Math, 'max', [1, 2]); // 返回 2
請注意,如果您必須跨不同來源傳輸錯誤,則您的報告端點需要支持跨域資源共享 (CORS)。
總結
如果您已經完成了這一步,那麼您現在擁有了所有必要的工具來滾動您自己的基本錯誤報告庫並將其與您的應用程序集成:
window.onerror
的工作原理及其支持的瀏覽器window.onerror
缺少的堆棧跟踪當然,如果您不想費心處理所有這些,有很多商業和開源工具可以為您完成客戶端報告的所有繁重工作。 (噓:您可能想嘗試使用 Sentry 來調試 JavaScript。)
就是這樣!祝您錯誤監控愉快。
關於使用 window.onerror 捕獲和報告 JavaScript 錯誤的常見問題解答 (FAQ)
window.onerror
函數在 JavaScript 中是如何工作的? JavaScript 中的 window.onerror
事件是一個全局事件處理程序,當執行 JavaScript 代碼時發生錯誤時會觸發。它是一個強大的調試和錯誤處理工具,因為它可以捕獲和報告未捕獲的異常或運行時錯誤。當發生錯誤時,window.onerror
函數將使用五個參數調用:錯誤消息、發生錯誤的 URL、行號、列號和 Error 對象。
window.onerror
和 try-catch 之間的區別是什麼? window.onerror
和 try-catch 都用於 JavaScript 中的錯誤處理,但它們的工作方式不同。 try-catch 語句允許您通過將可能引發錯誤的代碼包裝在 try 塊中,然後在 catch 塊中響應錯誤來直接處理錯誤。另一方面,window.onerror
是一個全局事件處理程序,當發生未捕獲的運行時錯誤時會觸發。它是一種更通用的錯誤處理機制,可以捕獲從 try-catch 塊中溜走的錯誤。
window.onerror
捕獲 JavaScript 錯誤? 要使用 window.onerror
,您需要定義一個函數,當發生錯誤時將調用該函數。此函數應採用五個參數:錯誤消息、發生錯誤的 URL、行號、列號和 Error 對象。在此函數內部,您可以根據需要處理錯誤。例如,您可以將錯誤記錄到控制台、向服務器發送報告或向用戶顯示消息。
window.onerror
可以捕獲所有類型的 JavaScript 錯誤嗎? 雖然 window.onerror
是一個強大的錯誤處理工具,但它確實有一些限制。它可以捕獲大多數未捕獲的運行時錯誤,但它無法捕獲在 try-catch 塊中拋出和捕獲的異常。此外,某些類型的錯誤(例如網絡錯誤或 CORS 錯誤)可能不會觸發 window.onerror
事件。
window.onerror
中使用 Error 對象? Error 對像是傳遞給 window.onerror
函數的第五個參數。它包含有關發生錯誤的信息,包括錯誤消息、錯誤名稱和堆棧跟踪。您可以使用此對象來獲取有關錯誤的更詳細信息,這對於調試或錯誤報告非常有用。
堆棧跟踪是一個報告,提供有關錯誤發生時程序執行路徑的信息。它顯示導致錯誤的函數調用序列,這對於調試非常有用。在 JavaScript 中,您可以從 Error 對象獲取堆棧跟踪。
在 JavaScript 中,您可以從 Error 對象獲取堆棧跟踪。當發生錯誤時,會創建一個 Error 對象並將其傳遞給 window.onerror
函數。此對像有一個名為 stack 的屬性,其中包含堆棧跟踪。您可以訪問此屬性以獲取堆棧跟踪。
window.onerror
將錯誤報告到服務器嗎? 是的,您可以使用 window.onerror
將錯誤報告到服務器。在您的 window.onerror
函數內部,您可以向服務器發送包含錯誤信息的請求。這對於監控和調試非常有用,因為它允許您實時收集和分析來自用戶的錯誤數據。
window.onerror
處理 CORS 錯誤? CORS 錯誤或跨域資源共享錯誤發生在 Web 應用程序嘗試訪問來自不同域的資源時。這些錯誤與安全相關,並且由於安全原因,不會向 window.onerror
事件處理程序提供詳細信息。但是,您可以通過向可能導致 CORS 錯誤的特定網絡請求添加錯誤處理程序來處理這些錯誤。
window.onerror
的一些最佳實踐是什麼? 使用 window.onerror
時,務必以不會中斷用戶體驗的方式處理錯誤。您應該避免向用戶顯示技術錯誤消息。相反,請考慮顯示友好的錯誤消息或靜默記錄錯誤。此外,請注意錯誤處理代碼的性能影響。例如,如果您要將錯誤報告發送到服務器,請確保異步執行此操作,以免阻塞主線程。
以上是用窗口捕獲和報告JavaScript錯誤。的詳細內容。更多資訊請關注PHP中文網其他相關文章!