摘要:錯(cuò)誤上報(bào)機(jī)制發(fā)送數(shù)據(jù)因?yàn)檎?qǐng)求本身也有可能會(huì)發(fā)生異常,而且有可能會(huì)引發(fā)跨域問(wèn)題,一般情況下更推薦使用動(dòng)態(tài)創(chuàng)建標(biāo)簽的形式進(jìn)行上報(bào)。
js錯(cuò)誤捕獲
js錯(cuò)誤的實(shí)質(zhì),也是發(fā)出一個(gè)事件,處理他
error實(shí)例對(duì)象
對(duì)象屬性
message:錯(cuò)誤提示信息
name:錯(cuò)誤名稱(非標(biāo)準(zhǔn)屬性)宿主環(huán)境賦予
stack:錯(cuò)誤的堆棧(非標(biāo)準(zhǔn)屬性)宿主環(huán)境賦予
對(duì)象類型(7種)
SyntaxError對(duì)象是解析代碼時(shí)發(fā)生的語(yǔ)法錯(cuò)誤
ReferenceError對(duì)象是引用一個(gè)不存在的變量時(shí)發(fā)生的錯(cuò)誤
RangeError對(duì)象是一個(gè)值超出有效范圍時(shí)發(fā)生的錯(cuò)誤(一是數(shù)組長(zhǎng)度為負(fù)數(shù),二是Number對(duì)象的方法參數(shù)超出范圍,以及函數(shù)堆棧超過(guò)最大值)
TypeError對(duì)象是變量或參數(shù)不是預(yù)期類型時(shí)發(fā)生的錯(cuò)誤:對(duì)字符串、布爾值、數(shù)值等原始類型的值使用new命令
URIError對(duì)象是 URI 相關(guān)函數(shù)的參數(shù)不正確時(shí)拋出的錯(cuò)誤:使用函數(shù)不當(dāng)
eval函數(shù)沒(méi)有被正確執(zhí)行時(shí),會(huì)拋出EvalError錯(cuò)誤 - 不再使用,為了代碼兼容
自定義錯(cuò)誤
function UserError(message) { this.message = message || "默認(rèn)信息"; this.name = "UserError"; } UserError.prototype = new Error(); UserError.prototype.constructor = UserError; new UserError("這是自定義的錯(cuò)誤!");Js運(yùn)行時(shí)錯(cuò)誤處理機(jī)制
try..catch…finally
范圍:用來(lái)捕獲任何類型的同步錯(cuò)誤,可以捕獲async / await的代碼,但無(wú)法捕獲promise、setTimeout、dom回調(diào)(eg:onclick點(diǎn)擊回調(diào))的代碼,在回調(diào)函數(shù)里面寫try…catch可以捕獲,但包在外面不會(huì)捕獲,無(wú)法捕獲語(yǔ)法錯(cuò)誤
異步不捕獲原因:
async/await捕獲原因:
window.onerror
范圍:同步錯(cuò)誤和異步錯(cuò)誤都可以捕獲,但無(wú)法捕獲到靜態(tài)資源異常,或者接口異常(網(wǎng)絡(luò)請(qǐng)求異常不會(huì)事件冒泡,因此必須在捕獲階段將其捕捉到才行),無(wú)法捕獲語(yǔ)法錯(cuò)誤
原理:當(dāng) JS 運(yùn)行時(shí)錯(cuò)誤發(fā)生時(shí),window 會(huì)觸發(fā)一個(gè) ErrorEvent 接口的 error 事件
參數(shù)
/** * @param {String} message 錯(cuò)誤信息 * @param {String} source 出錯(cuò)文件 * @param {Number} lineno 行號(hào) * @param {Number} colno 列號(hào)
*/ window.onerror = function(message, source, lineno, colno, error) { console.log("捕獲到異常:",{message, source, lineno, colno, error}); } ```
補(bǔ)充:window.onerror 函數(shù)只有在返回 true 的時(shí)候,異常才不會(huì)向上拋出,否則即使是知道異常的發(fā)生控制臺(tái)還是會(huì)顯示 Uncaught Error: xxxxx
onerror 最好寫在所有 JS 腳本的前面,否則有可能捕獲不到錯(cuò)誤;(捕獲的是全局錯(cuò)誤)
資源加載錯(cuò)誤window.addEventListener(一項(xiàng)資源(如圖片或腳本)加載失敗,加載資源的元素會(huì)觸發(fā)一個(gè) Event 接口的 error 事件,并執(zhí)行該元素上的onerror() 處理函數(shù),有瀏覽器兼容問(wèn)題)
注意:只能捕獲無(wú)法冒泡
window.addEventListener("error", (error) => { console.log("捕獲到異常:", error); }, true) // 一定要加true,捕獲但不冒泡
Script error跨域的靜態(tài)資源加載異常捕獲(cdn文件等)
跨域文件只會(huì)報(bào)Script error,沒(méi)有詳細(xì)信息,怎么解決:
客戶端:script標(biāo)簽添加crossOrigin
服務(wù)端:設(shè)置:Access-Control-Allow-Origin
iframe異常
使用window.onerror
promise異常捕獲
沒(méi)有寫 catch 的 Promise 中拋出的錯(cuò)誤無(wú)法被 onerror 或 try-catch 捕獲到
為了防止有漏掉的 Promise 異常,建議在全局增加一個(gè)對(duì) unhandledrejection 的監(jiān)聽(tīng),用來(lái)全局監(jiān)聽(tīng)Uncaught Promise Error
window.addEventListener("unhandledrejection", function(e){ console.log(e); });
補(bǔ)充:如果去掉控制臺(tái)的異常顯示,需要加上:event.preventDefault();
vue異常捕獲
VUE errorHandler
Vue.config.errorHandler = (err, vm, info) => { console.error("通過(guò)vue errorHandler捕獲的錯(cuò)誤"); console.error(err); console.error(vm); console.error(info); }React異常捕獲
componentDidCatch(React16)
新概念Error boundary(React16):UI的某部分引起的 JS 錯(cuò)誤不會(huì)破壞整個(gè)程序(只有 class component可以成為一個(gè) error boundaries)
不會(huì)捕獲以下錯(cuò)誤
1.事件處理器 2.異步代碼 3.服務(wù)端的渲染代碼 4.在 error boundaries 區(qū)域內(nèi)的錯(cuò)誤
Eg: 全局一個(gè)error boundary 組件就夠用啦
class ErrorBoundary extends React.Component { constructor(props) { super(props); this.state = { hasError: false }; } componentDidCatch(error, info) { // Display fallback UI this.setState({ hasError: true }); // You can also log the error to an error reporting service logErrorToMyService(error, info); } render() { if (this.state.hasError) { // You can render any custom fallback UI return頁(yè)面崩潰和卡頓處理Something went wrong.
; } return this.props.children; } }
卡頓
網(wǎng)頁(yè)暫時(shí)響應(yīng)比較慢, JS 可能無(wú)法及時(shí)執(zhí)行
解決:window 對(duì)象的 load 和 beforeunload 事件實(shí)現(xiàn)了網(wǎng)頁(yè)崩潰的監(jiān)控
window.addEventListener("load", function () { sessionStorage.setItem("good_exit", "pending"); setInterval(function () { sessionStorage.setItem("time_before_crash", new Date().toString()); }, 1000); }); window.addEventListener("beforeunload", function () { sessionStorage.setItem("good_exit", "true"); }); if(sessionStorage.getItem("good_exit") && sessionStorage.getItem("good_exit") !== "true") { /* insert crash logging code here */ alert("Hey, welcome back from your crash, looks like you crashed on: " + sessionStorage.getItem("time_before_crash")); }
崩潰
JS 都不運(yùn)行了,還有什么辦法可以監(jiān)控網(wǎng)頁(yè)的崩潰,并將網(wǎng)頁(yè)崩潰上報(bào)呢
解決:Service Worker 來(lái)實(shí)現(xiàn)網(wǎng)頁(yè)崩潰的監(jiān)控
Service Worker 有自己獨(dú)立的工作線程,與網(wǎng)頁(yè)區(qū)分開(kāi),網(wǎng)頁(yè)崩潰了,Service Worker一般情況下不會(huì)崩潰;
Service Worker 生命周期一般要比網(wǎng)頁(yè)還要長(zhǎng),可以用來(lái)監(jiān)控網(wǎng)頁(yè)的狀態(tài);
網(wǎng)頁(yè)可以通過(guò) navigator.serviceWorker.controller.postMessage API 向掌管自己的 SW發(fā)送消息。
錯(cuò)誤上報(bào)機(jī)制
Ajax 發(fā)送數(shù)據(jù)
因?yàn)?Ajax 請(qǐng)求本身也有可能會(huì)發(fā)生異常,而且有可能會(huì)引發(fā)跨域問(wèn)題,一般情況下更推薦使用動(dòng)態(tài)創(chuàng)建 img 標(biāo)簽的形式進(jìn)行上報(bào)。
動(dòng)態(tài)創(chuàng)建 img 標(biāo)簽的形式 更常用,簡(jiǎn)單,無(wú)跨越問(wèn)題
function report(error) { let reportUrl = "http://jartto.wang/report"; new Image().src = `${reportUrl}?logs=${error}`; }
如果你的網(wǎng)站訪問(wèn)量很大,那么一個(gè)必然的錯(cuò)誤發(fā)送的信息就有很多條,這時(shí)候,我們需要設(shè)置采集率,從而減緩服務(wù)器的壓力:
Reporter.send = function(data) { // 只采集 30% if(Math.random() < 0.3) { send(data) // 上報(bào)錯(cuò)誤信息 } }js源代碼壓縮如何定位:成熟方案提供sentry
sentry 是一個(gè)實(shí)時(shí)的錯(cuò)誤日志追蹤和聚合平臺(tái),包含了上面 sourcemap 方案,并支持更多功能,如:錯(cuò)誤調(diào)用棧,log 信息,issue管理,多項(xiàng)目,多用戶,提供多種語(yǔ)言客戶端等,
這里不過(guò)多敘述,之后在搭建sentry服務(wù)時(shí),會(huì)再補(bǔ)篇博文
補(bǔ)充:node服務(wù)端錯(cuò)誤處理機(jī)制全棧開(kāi)發(fā),后端采用express庫(kù),在這里補(bǔ)充一下,node服務(wù)的錯(cuò)誤處理方案
錯(cuò)誤分類
一般錯(cuò)誤處理:如某種回退,基本上只是說(shuō):“有錯(cuò)誤,請(qǐng)?jiān)僭囈淮位蚵?lián)系我們”。這并不是特別聰明,但至少通知用戶,有地方錯(cuò)了——而不是無(wú)限加載或進(jìn)行類似地處理
特殊錯(cuò)誤處理為用戶提供詳細(xì)信息,讓用戶了解有什么問(wèn)題以及如何解決它,例如,有信息丟失,數(shù)據(jù)庫(kù)中的條目已經(jīng)存在等等
步驟
1. 構(gòu)建一個(gè)自定義 Error 構(gòu)造函數(shù):讓我們方便地獲得堆棧跟蹤
class CustomError extends Error { constructor(code = "GENERIC", status = 500, ...params) { super(...params) if (Error.captureStackTrace) { Error.captureStackTrace(this, CustomError) } this.code = code this.status = status } } module.exports = CustomError
2.處理路由:對(duì)于每一個(gè)路由,我們要有相同的錯(cuò)誤處理行為
wT:在默認(rèn)情況下,由于路由都是封裝的,所以 Express 并不真正支持那種方式
解決:實(shí)現(xiàn)一個(gè)路由處理程序,并把實(shí)際的路由邏輯定義為普通的函數(shù)。這樣,如果路由功能(或任何內(nèi)部函數(shù))拋出一個(gè)錯(cuò)誤,它將返回到路由處理程序,然后可以傳給前端
const express = require("express") const router = express.Router() const CustomError = require("../CustomError") router.use(async (req, res) => { try { const route = require(`.${req.path}`)[req.method] try { const result = route(req) // We pass the request to the route function res.send(result) // We just send to the client what we get returned from the route function } catch (err) { /* This will be entered, if an error occurs inside the route function. */ if (err instanceof CustomError) { /* In case the error has already been handled, we just transform the error to our return object. */ return res.status(err.status).send({ error: err.code, description: err.message, }) } else { console.error(err) // For debugging reasons // It would be an unhandled error, here we can just return our generic error object. return res.status(500).send({ error: "GENERIC", description: "Something went wrong. Please try again or contact support.", }) } } } catch (err) { /* This will be entered, if the require fails, meaning there is either no file with the name of the request path or no exported function with the given request method. */ res.status(404).send({ error: "NOT_FOUND", description: "The resource you tried to access does not exist.", }) } }) module.exports = router // 實(shí)際路由文件 const CustomError = require("../CustomError") const GET = req => { // example for success return { name: "Rio de Janeiro" } } const POST = req => { // example for unhandled error throw new Error("Some unexpected error, may also be thrown by a library or the runtime.") } const DELETE = req => { // example for handled error throw new CustomError("CITY_NOT_FOUND", 404, "The city you are trying to delete could not be found.") } const PATCH = req => { // example for catching errors and using a CustomError try { // something bad happens here throw new Error("Some internal error") } catch (err) { console.error(err) // decide what you want to do here throw new CustomError( "CITY_NOT_EDITABLE", 400, "The city you are trying to edit is not editable." ) } } module.exports = { GET, POST, DELETE, PATCH, }
3.構(gòu)建全局錯(cuò)誤處理機(jī)制
process.on("uncaughtException", (error: any) => { logger.error("uncaughtException", error) }) process.on("unhandledRejection", (error: any) => { logger.error("unhandledRejection", error) })總結(jié):
1.可疑區(qū)域增加 Try-Catch
2.全局監(jiān)控 JS 異常 window.onerror
3.全局監(jiān)控靜態(tài)資源異常 window.addEventListener
4.捕獲沒(méi)有 Catch 的 Promise 異常:unhandledrejection
5.VUE errorHandler 和 React componentDidCatch
6.監(jiān)控網(wǎng)頁(yè)崩潰:window 對(duì)象的 load 和 beforeunload
7.跨域 crossOrigin 解決
http://jartto.wang/2018/11/20...
https://levelup.gitconnected....
https://zhuanlan.zhihu.com/p/... 更詳細(xì) 待補(bǔ)充
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/109644.html
摘要:五六月份推薦集合查看最新的請(qǐng)點(diǎn)擊集前端最近很火的框架資源定時(shí)更新,歡迎一下。蘇幕遮燎沈香宋周邦彥燎沈香,消溽暑。鳥(niǎo)雀呼晴,侵曉窺檐語(yǔ)。葉上初陽(yáng)乾宿雨,水面清圓,一一風(fēng)荷舉。家住吳門,久作長(zhǎng)安旅。五月漁郎相憶否。小楫輕舟,夢(mèng)入芙蓉浦。 五、六月份推薦集合 查看github最新的Vue weekly;請(qǐng)::點(diǎn)擊::集web前端最近很火的vue2框架資源;定時(shí)更新,歡迎 Star 一下。 蘇...
摘要:五六月份推薦集合查看最新的請(qǐng)點(diǎn)擊集前端最近很火的框架資源定時(shí)更新,歡迎一下。蘇幕遮燎沈香宋周邦彥燎沈香,消溽暑。鳥(niǎo)雀呼晴,侵曉窺檐語(yǔ)。葉上初陽(yáng)乾宿雨,水面清圓,一一風(fēng)荷舉。家住吳門,久作長(zhǎng)安旅。五月漁郎相憶否。小楫輕舟,夢(mèng)入芙蓉浦。 五、六月份推薦集合 查看github最新的Vue weekly;請(qǐng)::點(diǎn)擊::集web前端最近很火的vue2框架資源;定時(shí)更新,歡迎 Star 一下。 蘇...
摘要:關(guān)于,強(qiáng)烈推薦閱讀跨域資源共享詳解阮一峰另外,這里也整理了一個(gè)實(shí)現(xiàn)原理圖簡(jiǎn)化版如何判斷是否是簡(jiǎn)單請(qǐng)求瀏覽器將請(qǐng)求分成兩類簡(jiǎn)單請(qǐng)求和非簡(jiǎn)單請(qǐng)求。 前言 從剛接觸前端開(kāi)發(fā)起,跨域這個(gè)詞就一直以很高的頻率在身邊重復(fù)出現(xiàn),一直到現(xiàn)在,已經(jīng)調(diào)試過(guò)N個(gè)跨域相關(guān)的問(wèn)題了,16年時(shí)也整理過(guò)一篇相關(guān)文章,但是感覺(jué)還是差了點(diǎn)什么,于是現(xiàn)在重新梳理了一下。 個(gè)人見(jiàn)識(shí)有限,如有差錯(cuò),請(qǐng)多多見(jiàn)諒,歡迎提出iss...
摘要:希望幫助更多的前端愛(ài)好者學(xué)習(xí)。前端開(kāi)發(fā)者指南作者科迪林黎,由前端大師傾情贊助。翻譯最佳實(shí)踐譯者張捷滬江前端開(kāi)發(fā)工程師當(dāng)你問(wèn)起有關(guān)與時(shí),老司機(jī)們首先就會(huì)告訴你其實(shí)是個(gè)沒(méi)有網(wǎng)絡(luò)請(qǐng)求功能的庫(kù)。 前端基礎(chǔ)面試題(JS部分) 前端基礎(chǔ)面試題(JS部分) 學(xué)習(xí) React.js 比你想象的要簡(jiǎn)單 原文地址:Learning React.js is easier than you think 原文作...
閱讀 6866·2021-09-22 15:36
閱讀 5687·2021-09-02 10:20
閱讀 1869·2019-08-30 15:44
閱讀 2653·2019-08-29 14:06
閱讀 1153·2019-08-29 11:17
閱讀 1585·2019-08-26 14:05
閱讀 3093·2019-08-26 13:50
閱讀 1551·2019-08-26 10:26