前言
做好錯誤監(jiān)控,將用戶使用時的錯誤日志上報,可以幫助我們更快的解決一些問題。
那前端監(jiān)控是怎么實現(xiàn)的呢?要想了解這個,需要知道前端錯誤大概分為哪些以及如何捕獲處理。
前端錯誤分為JS運行時錯誤、資源加載錯誤和接口錯誤三種。
本文檔介紹有關(guān)js的錯誤類型、錯誤事件、vue3的app.config.errorHandler全局處理函數(shù)。
用nodejs+Express模擬接口,將監(jiān)聽到的錯誤信息發(fā)送到nodejs寫的接口里,再通過一個getErrorList接口展示錯誤信息列表。
js的錯誤對象和onerror事件
2.1錯誤對象類型
ECMA-262定義了下列7種錯誤類型:https://baike.baidu.com/item/ECMAScript/1889420?fr=aladdin
Error() // 基類型
EvalError() // eval錯誤
RangeError() // 范圍錯誤
ReferenceError() // 引用錯誤
SyntaxError() // 語法錯誤
TypeError() // 類型錯誤
URIError() // URI錯誤
Error: 所有錯誤類型的父類型。
SyntaxError: 語法錯誤,表示程序的語法使用錯誤。
console.log(【】) ; VM115:1 Uncaught SyntaxError: Invalid or unexpected token
ReferenceError: 引用錯誤,表示引用的變量不存在。
console.log(a) ; VM274:1 Uncaught ReferenceError: a is not defined at <anonymous>:1:13
TypeError: 類型錯誤,表示使用了錯誤的數(shù)據(jù)類型。
let a; console.log(a.name); VM279:2 Uncaught TypeError: Cannot read properties of undefined (reading 'name') at <anonymous>:2:15
RangeError:范圍錯誤, 數(shù)據(jù)值不在其所允許的范圍內(nèi)(函數(shù)遞歸調(diào)用容易出現(xiàn)此錯誤)。
(10.24).toFixed(-1)
VM363:2 Uncaught RangeError: toFixed() digits argument must be between 0 and 100
at Number.toFixed (<anonymous>)
at <anonymous>:2:9
URIError: URI錯誤,向全局 URI 處理函數(shù)(decodeURI、decodeURIComponent)傳遞一個不合法的URI時,URIError 錯誤會被拋出。
// 解碼URI地址 錯誤:格式不正確
console.log(decodeURI("%") );
VM368:2 Uncaught URIError: URI malformed
at decodeURI (<anonymous>)
at <anonymous>:2:13
EvelError: eval函數(shù)執(zhí)行錯誤 EvalError 不在當(dāng)前ECMAScript規(guī)范中使用,因此不會被運行時拋出。但是對象本身仍然與規(guī)范的早期版本向后兼容。
通過error的構(gòu)造器可以創(chuàng)建一個錯誤對象。如 new error() throw new Error(); 這個是創(chuàng)建錯誤,創(chuàng)造一個錯誤類型拋出。
?
// 拋出的地方
function parseExcel(con) {
try {
// doSomething
} catch (error) {
throw new Error('parse excel failed');
}
}
// 捕獲的地方
try {
parseExcel(con);
} catch (error) {
if (error.message === 'parse excel failed') {
//doSomething
}
}
2.2Error對象
--error 對象是當(dāng)錯誤發(fā)生時提供錯誤信息的 JS 內(nèi)置對象。
當(dāng)錯誤發(fā)生時,瀏覽器會生成 error 對象并拋出,并且中斷后面代碼的執(zhí)行。
console.log(js)
console.log('中斷后面代碼的執(zhí)行,不會被執(zhí)行到')
VM488:1 Uncaught ReferenceError: js is not defined
at <anonymous>:1:13
任何沒有通過try-catch處理的錯誤都會觸發(fā)window對象的error事件。
error事件接收五個參數(shù):
message:錯誤信息(字符串)
source:發(fā)生錯誤的腳本URL(字符串)
lineno:發(fā)生錯誤的行號(數(shù)字)
colno:發(fā)生錯誤的列號(數(shù)字)
error:Error對象(對象)
?
?
圖像也支持error事件。
var img = new Image()
img.src='a.jpg'
img.onerror = function(e) {
console.log(e)
}
2.3資源加載失敗
window.addEventListener 當(dāng)一項資源(如圖片或腳本)加載失敗,加載資源的元素會觸發(fā)一個 Event 接口的 error 事件,這些 error 事件不會向上冒泡到 window,但能被捕獲。而window.onerror不能監(jiān)測捕獲。
// 圖片、script、css加載錯誤,都能被捕獲 ?
<script>
window.addEventListener('error', (error) => {
console.log('捕獲到異常:', error);
}, true)
</script>
<img src="https://yun.tuia.cn/image/kkk.png">
<script src="https://yun.tuia.cn/foundnull.js"></script>
<link rel="stylesheet"/>
// new Image錯誤,不能捕獲 ?
<script>
window.addEventListener('error', (error) => {
console.log('捕獲到異常:', error);
}, true)
</script>
<script>
new Image().src = 'https://yun.tuia.cn/image/lll.png'
</script>
// fetch錯誤,不能捕獲 ?
<script>
window.addEventListener('error', (error) => {
console.log('捕獲到異常:', error);
}, true)
</script>
<script>
fetch('https://tuia.cn/test')
</script>
到目前為止,還有語法錯誤、promise異步錯誤、new Image資源加載錯誤還沒有捕獲方法。
語法錯誤可以在開發(fā)階段依靠編輯器發(fā)現(xiàn)。
new Image運用的比較少,可以單獨自己處理自己的錯誤,可以通過img.onerror = fn來單獨處理。
但通用的fetch怎么辦呢,fetch返回Promise,但Promise的錯誤不能被捕獲,怎么辦呢?
Promise錯誤
1.普通Promise錯誤
try/catch不能捕獲Promise中的錯誤
// try/catch 不能處理 JSON.parse 的錯誤,因為它在 Promise 中
try {
new Promise((resolve,reject) => {
JSON.parse('')
resolve();
})
} catch(err) {
console.error('in try catch', err)
}
// 需要使用catch方法
new Promise((resolve,reject) => {
JSON.parse('')
resolve();
}).catch(err => {
console.log('in catch fn', err)
})
2.async錯誤
try/catch不能捕獲async包裹的錯誤
const getJSON = async () => {
throw new Error('inner error')
}
// 通過try/catch處理
const makeRequest = async () => {
try {
// 捕獲不到
JSON.parse(getJSON());
} catch (err) {
console.log('outer', err);
}
};
try {
// try/catch不到
makeRequest()
} catch(err) {
console.error('in try catch', err)
}
try {
// 需要await,才能捕獲到
await makeRequest()
} catch(err) {
console.error('in try catch', err)
}
3.import chunk錯誤
import其實返回的也是一個promise,因此使用如下兩種方式捕獲錯誤
// Promise catch方法
import(/* webpackChunkName: "incentive" */'./index').then(module => {
module.default()
}).catch((err) => {
console.error('in catch fn', err)
})
// await 方法,try catch
try {
const module = await import(/* webpackChunkName: "incentive" */'./index');
module.default()
} catch(err) {
console.error('in try catch', err)
}
小結(jié):全局捕獲Promise中的錯誤
以上三種其實歸結(jié)為Promise類型錯誤,可以通過unhandledrejection捕獲。 為了防止有漏掉的 Promise 異常,可通過unhandledrejection用來全局監(jiān)聽Uncaught Promise Error。
// 全局統(tǒng)一處理Promise
window.addEventListener("unhandledrejection", function(e){
console.log('捕獲到異常:', e);
});
fetch('https://tuia.cn/test')
當(dāng)promise被reject并且錯誤信息沒有被處理的時候,會拋出一個unhandledrejection,并且這個錯誤不會被window.onerror以及window.addEventListener('error')捕獲,需要用專門的window.addEventListener('unhandledrejection')捕獲處理。
window.addEventListener('unhandledrejection', event =>
{
console.log('unhandledrejection:' + event.reason); // 捕獲后自定義處理
});
https://developer.mozilla.org... 例子: http://sandbox.runjs.cn/show/eatrbc1w 請打開頁面打開控制臺查看。點擊button拋出unhandledrejection錯誤,并且該錯誤僅能被window.addEventListener('unhandledrejection')捕獲。
Uncaught RangeError: Maximum call stack
這是Chrome瀏覽器在幾種情況下出現(xiàn)的錯誤,一種是調(diào)用不終止的遞歸函數(shù)。你可以在Chrome開發(fā)者控制臺中對此進(jìn)行測試。
8、js FileReader 讀取文件錯誤處理
const reader = new FileReader()
reader.onload = ()=>{}
reader.οnerrοr= ()=>{}
9、圖片onerror事件
img標(biāo)簽支持onerror 事件,在裝載文檔或圖像的過程中如果發(fā)生了錯誤,就會觸發(fā)onerror事件??梢允褂靡粡?zhí)崾惧e誤的圖片代替顯示不了的圖片。
10、其他資源的onerror事件---腳本、iframe等
瀏覽器允許我們跟蹤外部資源的加載 —— 腳本,iframe,圖片等。
因此,在 onload 中我們可以使用腳本中的變量,運行函數(shù)等。 ……如果加載失敗怎么辦?例如,這里沒有這樣的腳本(error 404)或者服務(wù)器宕機(不可用)。
發(fā)生在腳本加載期間的 error 會被 error
事件跟蹤到。
例如,我們請求一個不存在的腳本:
let script = document.createElement('script');
script.src = "https://example.com/404.js"; // 沒有這個腳本
document.head.append(script);
script.onerror = function() {
alert("Error loading " + this.src); // Error loading https://example.com/404.js
};
請注意,在這里我們無法獲取更多 HTTP error 的詳細(xì)信息。我們不知道 error 是 404 還是 500 或者其他情況。只知道是加載失敗了。
-
對于
<iframe>
來說,iframe 加載完成時會觸發(fā)iframe.onload
事件,無論是成功加載還是出現(xiàn) error。
1.5 特別說明sourceMap
在線上由于JS一般都是被壓縮或者打包(webpack)過,打包后的文件只有一行,因此報錯會出現(xiàn)第一行第5000列出現(xiàn)JS錯誤,給排查帶來困難。sourceMap存儲打包前的JS文件和打包后的JS文件之間一個映射關(guān)系,可以根據(jù)打包后的位置快速解析出對應(yīng)源文件的位置。
但是出于安全性考慮,線上設(shè)置sourceMap會存在不安全的問題,因為網(wǎng)站使用者可以輕易的看到網(wǎng)站源碼,此時可以設(shè)置.map文件只能通過公司內(nèi)網(wǎng)訪問降低隱患
sourceMap配置devtool: 'inline-source-map' 如果使用了uglifyjs-webpack-plugin 必須把 sourceMap設(shè)置為true https://doc.webpack-china.org...https://doc.webpack-china.org/guides/development/#%E4%BD%BF%E7%94%A8-source-map
三、vue的app.config.errorHandler全局處理函數(shù)
由于Vue會捕獲所有Vue單文件組件或者Vue.extend繼承的代碼,所以在Vue里面出現(xiàn)的錯誤,并不會直接被window.onerror捕獲,而是會拋給Vue.config.errorHandler。
app.config.errorHandler用于為應(yīng)用內(nèi)拋出的未捕獲錯誤指定一個全局處理函數(shù)。https://cn.vuejs.org/api/application.html#app-config-errorhandler
-
詳細(xì)信息
-
錯誤處理器接收三個參數(shù):錯誤對象、觸發(fā)該錯誤的組件實例和一個指出錯誤來源類型信息的字符串。
-
它可以從下面這些來源中捕獲錯誤:
-
組件渲染器
-
事件處理器
-
生命周期鉤子
-
setup()
函數(shù) -
偵聽器
-
自定義指令鉤子
-
過渡 (Transition) 鉤子文章來源:http://www.zghlxwxcb.cn/news/detail-774807.html
-
import { createApp } from 'vue'
import App from './App.vue'
let app = createApp(App)
app.config.errorHandler = (err, vm, info) => {
console.log(123)
// err:
// vm:
// info: 是vue特定的錯誤信息,比如錯誤所在的生命周期鉤子
console.log(err, vm, info);
fetch("http://127.0.0.1:8081/process_post", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
mode: "no-cors",
body: JSON.stringify({
errorMsg: err
})
}).then(function(res) {
if (res.status === 200) {
return res.json()
} else {
//return Promise.reject(res.json())
}
}).then(function(data) {
console.log(data);
}).catch(function(err) {
console.log(err);
});
}
app.mount('#app')
僅供參考,侵權(quán)必刪。文章來源地址http://www.zghlxwxcb.cn/news/detail-774807.html
到了這里,關(guān)于前端錯誤收集與處理的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!