前言
这是学习源码整体架构第四篇。整体架构这词语好像有点大,姑且就算是源码整体结构吧,主要就是学习是代码整体结构,不深究其他不是主线的具体函数的实现。文章学习的是打包整合后的代码,不是实际仓库中的拆分的代码。
其余三篇分别是:
1.学习 jQuery 源码整体架构,打造属于自己的 js 类库
感兴趣的读者可以点击阅读。
导读
本文通过梳理前端错误监控知识、介绍 sentry
错误监控原理、 sentry
初始化、 Ajax
上报、 window.onerror、window.onunhandledrejection
几个方面来学习 sentry
的源码。
开发微信小程序,想着搭建小程序错误监控方案。最近用了丁香园 开源的 Sentry
小程序 SDK
sentry-miniapp。 顺便研究下 sentry-javascript
仓库 的源码整体架构,于是有了这篇文章。
本文分析的是打包后未压缩的源码,源码总行数五千余行,链接地址是:https://browser.sentry-cdn.com/5.7.1/bundle.js, 版本是 v5.7.1
。
本文示例等源代码在这我的 github
博客中github blog sentry,需要的读者可以点击查看,如果觉得不错,可以顺便 star
一下。
看源码前先来梳理下前端错误监控的知识。
前端错误监控知识
摘抄自 慕课网视频教程:前端跳槽面试必备技巧
别人做的笔记:前端跳槽面试必备技巧-4-4 错误监控类
前端错误的分类
1.即时运行错误:代码错误
try...catch
window.onerror
(也可以用 DOM2
事件监听)
2.资源加载错误
object.onerror
: dom
对象的 onerror
事件
performance.getEntries()
Error
事件捕获
3.使用
performance.getEntries()
获取网页图片加载错误
varallImgs=document.getElementsByTagName('image')
varloadedImgs=performance.getEntries().filter(i=>i.initiatorType==='img')
最后 allIms
和 loadedImgs
对比即可找出图片资源未加载项目
Error事件捕获代码示例
window.addEventListener('error', function(e) {
console.log('捕获', e)
}, true) // 这里只有捕获才能触发事件,冒泡是不能触发
上报错误的基本原理
1.采用 Ajax
通信的方式上报
2.利用 Image
对象上报 (主流方式)
Image
上报错误方式: (newImage()).src='https://lxchuan12.cn/error?name=若川'
Sentry 前端异常监控基本原理
1.重写
window.onerror
方法、重写window.onunhandledrejection
方法
如果不了解 onerror和onunhandledrejection
方法的读者,可以看相关的 MDN
文档。这里简要介绍一下:
MDN GlobalEventHandlers.onerror
window.onerror = function (message, source, lineno, colno, error) {
console.log('message, source, lineno, colno, error', message, source, lineno, colno, error);
}
参数:
message
:错误信息(字符串)。可用于HTML onerror=""
处理程序中的event
。source
:发生错误的脚本URL
(字符串)lineno
:发生错误的行号(数字)colno
:发生错误的列号(数字)error
:Error
对象(对象)
MDN unhandledrejection
当
Promise
被reject
且没有reject
处理器的时候,会触发unhandledrejection
事件;这可能发生在window
下,但也可能发生在Worker
中。 这对于调试回退错误处理非常有用。
Sentry
源码可以搜索 global.onerror
定位到具体位置
GlobalHandlers.prototype._installGlobalOnErrorHandler = function () {
// 代码有删减
// 这里的 this._global 在浏览器中就是 window
this._oldOnErrorHandler = this._global.onerror;
this._global.onerror = function (msg, url, line, column, error) {}
// code ...
}
同样,可以搜索 global.onunhandledrejection
定位到具体位置
GlobalHandlers.prototype._installGlobalOnUnhandledRejectionHandler = function () {
// 代码有删减
this._oldOnUnhandledRejectionHandler = this._global.onunhandledrejection;
this._global.onunhandledrejection = function (e) {}
}
2.采用
Ajax
上传
支持 fetch
使用 fetch
,否则使用 XHR
。
BrowserBackend.prototype._setupTransport = function () {
// 代码有删减
if (supportsFetch()) {
return new FetchTransport(transportOptions);
}
return new XHRTransport(transportOptions);
};
2.1
fetch
FetchTransport.prototype.sendEvent = function (event) {
var defaultOptions = {
body: JSON.stringify(event),
method: 'POST',
referrerPolicy: (supportsReferrerPolicy() ? 'origin' : ''),
};
return this._buffer.add(global$2.fetch(this.url, defaultOptions).then(function (response) { return ({
status: exports.Status.fromHttpCode(response.status),
}); }));
};
2.2
XMLHttpRequest
XHRTransport.prototype.sendEvent = function (event) {
var _this = this;
return this._buffer.add(new SyncPromise(function (resolve, reject) {
// 熟悉的 XMLHttpRequest
var request = new XMLHttpRequest();
request.onreadystatechange = function () {
if (request.readyState !