前端的异常场景
- Javascript 运行错误
- 异步异常
- 网络加载错误
- HTTP 请求错误
Javascript 运行错误
- EvalError:在
eval()
函数中发送的错误 - InternalError:内部错误
- 比如递归太深,导致卡死
- RangeError:超出数字范围的错误
- 比如数组越界
- ReferenceError:非法引用
- 变量未定义
- SyntaxError:语法错误
- TypeError:类型错误
- URIError:在
encodeURI()
中发生的错误
异步异常
- setTimeout
- setInterval
- Promise
- requestAnimationFrame
捕获异常需要在内部加才能生效。
网络加载错误
异常的捕获
try catch
try {
var name = 55
console.log(anme)
} catch(err) {
console.log(err);
}
window.onerror 全局捕获
window.onerror
和 window.addEventListener('error', () => { })
两者相同点
- 都能捕获代码运行时的错误。
后者可以捕获网络加载错误,前者不能
window.onerror = (message, source, lineno, colno, error) => {
console.log(message);// 错误信息
console.log(source); // 源文件 url 路径
console.log(lineno); // 第几行
console.log(colno); // 第几列
console.log(error); // 错误信息,以及出错代码的 url 连接
}
window.addEventListener('error', (errorEvent) => {
const { message, filename, lineno, colno, error } = errorEvent
console.log(message);
console.log(filename)
console.log(lineno)
console.log(colno);
console.log(error);
})
console.log(asdf)
捕获 promise 异常
window.addEventListener('unhandledrejection', function (event) {
// 处理未处理的拒绝
// 防止默认错处(例如将错误输出到控制台)
event.preventDefault();
})
跨域 script error
浏览器只允许同域下的脚本捕获具体的错误信息。
解决方法有两种
- script 脚本设置
crossorigin="anonymous"
,并且服务器响应头设置Access-Control-Origin: *(或者当前域名)
服务端响应头
Access-Control-Origin: *(或者当前域名)
- 重写浏览器
addEventListener
方法 ```javascript const orignAddEventListener = EventTarget.prototype.addEventListener;
EventTarget.prototype.addEventListener = function (type, listener, options) { const wrappedListener = function (…args) { try { return listener.apply(this, args); } catch (error) { throw err } } return orignAddEventListener.call(this, type, wrappedListener, options) }
<a name="XuSIg"></a>
## Vue error handler
![image.png](https://cdn.nlark.com/yuque/0/2022/png/1174243/1645454032561-7254aac0-b0f5-4795-b3f8-4afe828d60a0.png#clientId=u31ea2781-9f7f-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=226&id=udd5f6114&margin=%5Bobject%20Object%5D&name=image.png&originHeight=282&originWidth=866&originalType=binary&ratio=1&rotation=0&showTitle=false&size=78516&status=done&style=none&taskId=ud3d08e6b-6d01-4432-ab68-a2242b35650&title=&width=692.8)
<a name="dt57T"></a>
## HTTP 请求错误
重写 fetch 和 XMLHttpRequest<br />![image.png](https://cdn.nlark.com/yuque/0/2022/png/1174243/1645454095240-b517e46f-497a-4fb5-89de-02fb23709632.png#clientId=u31ea2781-9f7f-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=526&id=u8d961bea&margin=%5Bobject%20Object%5D&name=image.png&originHeight=658&originWidth=865&originalType=binary&ratio=1&rotation=0&showTitle=false&size=187465&status=done&style=none&taskId=u337a86be-c705-4289-aba0-96877cf7a15&title=&width=692)
<a name="nvIVb"></a>
## 网页崩溃
使用 Server worker 来监控。
<a name="vUAPH"></a>
# 错误上报
- XMLHttpRequest
- navigator.sendBeacon
- IndexedDB 缓存,异步上传
- 页面截图(html2canvas)
<a name="uL7GZ"></a>
# SourceMap
sourceMap 文件
```json
{
version : 3,
file: "out.js",
sourceRoot : "",
sources: ["foo.js", "bar.js"],
names: ["src", "maps", "are", "fun"],
mappings: "AAgBC,SAAQ,CAAEA"
}
错误堆栈查看工具
UglifyJS 反向美化
const UglifyJS = require('uglify-js');
const fs = require('fs');
const path = require('path');
const sourceMap = require('source-map');
const source = fs.readFileSync(path.join(__dirname, './promise.js')).toString()
const result = UglifyJS.minify(source, {
output: {
beautify: true
},
sourceMap: {
filename: 'promise.js',
url: 'promise.js.map'
}
})
const code = result.code;
const rawSourceMap = JSON.parse(result.map);
const consumerPromise = new sourceMap.SourceMapConsumer(rawSourceMap);
consumerPromise.then(consumer => ({
code: code,
sourceMapConsumer: consumer
})).then(result => {
console.log(result)
})
vscode 使用的编辑器:https://github.com/microsoft/monaco-editor
Sentry
参考资料
《JavaScript Source Map 详解》
《从 0 到 1 搭建前端监控系统之异常监控》
《Source Map》