icon-cookie
The website uses cookies to optimize your user experience. Using this website grants us the permission to collect certain information essential to the provision of our services to you, but you may change the cookie settings within your browser any time you wish. Learn more
I agree
blank_error__heading
blank_error__body
Text direction?

从0到1,Vue大牛的前端搭建——异常监控系统

一个默默工作十年的前端工程师

本篇文章读后,你将GET的技能:

●收集前端错误(原生、React、Vue)

●编写错误上报逻辑

●利用Egg.js编写一个错误日志采集服务

●编写webpack插件自动上传sourcemap

●利用sourcemap还原压缩代码源码位置

●利用Jest进行单元测试

有没有心动的感觉?赶紧学起来吧!

(1)如何捕获异常

JS异常:

js异常的特点是,出现不会导致JS引擎崩溃 最多只会终止当前执行的任务。

比如一个页面有两个按钮,如果点击按钮发生异常页面,这个时候页面不会崩溃。

只是这个按钮的功能失效,其他按钮还会有效☟

上面的例子我们用setTimeout分别启动了两个任务。

虽然第一个任务执行了一个错误的方法。程序执行停止了。但是另外一个任务并没有收到影响。

其实如果你不打开控制台都看不到发生了错误。好像是错误是在静默中发生的。

三天时间,能使用Vue3.0新语法开发项目,从源码层面分析Vue3.0,掌握新的响应式 vdom架构:

下面我们来看看这样的错误该如何收集。

try-catch:

JS作为一门高级语言我们首先想到的使用try-catch来收集。

如果在函数中错误没有被捕获,错误会上抛。

控制台中打印出的分别是错误信息和错误堆栈。

读到这里大家可能会想那就在最底层做一个错误try-catch不就好了吗。

确实作为一个从java转过来的程序员也是这么想的。

但是理想很丰满,现实很骨感。我们看看下一个例子。

大家注意运行结果,异常并没有被捕获。

这是因为JS的try-catch功能非常有限一遇到异步就不好用了。

那总不能为了收集错误给所有的异步都加一个try-catch吧,太坑爹了。

其实你想想异步任务其实也不是由代码形式上的上层调用的就比如本例中的settimeout。

大家想想eventloop就明白啦,其实这些一步函数都是就好比一群没娘的孩子出了错误找不到家大人。

当然我也想过一些黑魔法来处理这个问题比如代理执行或者用过的异步方法。

算了还是还是再看看吧。

(2)异常任务捕获

window.onerror:

window.onerror 最大的好处就是可以同步任务还是异步任务都可捕获。

onerror返回值

onerror还有一个问题大家要注意 如果返回返回true 就不会被上抛了。

不然控制台中还会看到错误日志。

监听error事件:

文件中的位置☟

window.addEventListener('error',() => {})

其实onerror固然好但是还是有一类异常无法捕获。这就是网络异常的错误。

比如下面的例子。

<img src="./xxxxx.png">

试想一下我们如果页面上要显示的图片突然不显示了,而我们浑然不知那就是麻烦了。

addEventListener就是☟

运行结果如下☟

Promise异常捕获:

Promise的出现主要是为了让我们解决回调地域问题。基本是我们程序开发的标配了。

虽然我们提倡使用es7 async/await语法来写。

但是不排除很多祖传代码还是存在Promise写法。

new Promise((resolve, reject) => {
  abcxxx()
});

这种情况无论是onerror还是监听错误事件都是无法捕获的。

除非每个Promise都添加一个catch方法。

但显然,我们不能这样做。

window.addEventListener("unhandledrejection", e => {
 console.log('unhandledrejection',e)
});

我们可以考虑将unhandledrejection事件捕获错误抛出交由错误事件统一处理就可以了。

async/await异常捕获:

实际上async/await语法本质还是Promise语法。

区别就是async方法可以被上层的try/catch捕获。

如果不去捕获的话就会和Promise一样,需要用unhandledrejection事件捕获。

这样的话我们只需要在全局增加unhandlerejection就好了。

小结:

实际上我们可以将unhandledrejection事件抛出的异常再次抛出就可以统一通过error事件进行处理了。

最终用代码表示如下:

三天时间,能使用Vue3.0新语法开发项目,从源码层面分析Vue3.0,掌握新的响应式 vdom架构:

(3)前端工程化

Webpack工程化:

现在是前端工程化的时代,工程化导出的代码一般都是被压缩混淆后的。

比如:

setTimeout(() => {
    xxx(1223)
}, 1000)

出错的代码指向被压缩后的JS文件,而JS文件长下图这个样子。

如果想将错误和原有的代码关联起来,那就需要sourcemap文件的帮忙了。

sourceMap是什么?

简单说,sourceMap就是一个文件,里面储存着位置信息。

仔细点说,这个文件里保存的,是转换后代码的位置,和对应的转换前的位置。

那么如何利用sourceMap对还原异常代码发生的位置这个问题,我们到异常分析这个章节再讲。

(4)VUE创建工程

利用vue-cli工具直接创建一个项目。

为了测试的需要我们暂时关闭eslint 这里面还是建议大家全程打开eslint。

在vue.config.js进行配置

我们故意在(文件位置☟)

src/components/HelloWorld.vue

这个时候 错误会在控制台中被打印出来,但是错误事件并没有监听到。

handleError:

为了对Vue发生的异常进行统一的上报,需要利用vue提供的handleError句柄。

一旦Vue发生异常都会调用这个方法。

我们在src/main.js

React:

npx create-react-app react-sample

cd react-sample

yarn start

我们l用useEffect hooks 制造一个错误:

并且在src/index.js中增加错误事件监听逻辑:

window.addEventListener('error', args => {
    console.log('error', error)
})

但是从运行结果看虽然输出了错误日志但是还是服务捕获。

(5)Error Boundary 标签

错误边界仅可以捕获其子组件的错误。

错误边界无法捕获其自身的错误。

如果一个错误边界无法渲染错误信息,则错误会向上冒泡至最接近的错误边界。

这也类似于 JavaScript 中 catch {} 的工作机制。

创建ErrorBoundary组件

在src/index.js中包裹App标签☟

最终运行的结果:

关于Ajax的异常上报、搭建eggis工程、深度解析Error Staack等等操作,我正在拼命制作中,感兴趣的朋友记得关注我,产出后我会第一时间发出来~

以上,希望能够帮助到各位。

三天时间,能使用Vue3.0新语法开发项目,从源码层面分析Vue3.0,掌握新的响应式 vdom架构:

Measure
Measure
Related Notes
Get a free MyMarkup account to save this article and view it later on any device.
Create account

End User License Agreement

Summary | 8 Annotations
window.onerror
2020/06/06 09:24
返回true 就不会被上抛了
2020/06/06 09:24
Webpack工程化
2020/06/06 09:25
前端工程化的时代,工程化导出的代码一般都是被压缩混淆后的
2020/06/06 09:25
sourceMap
2020/06/06 09:25
sourceMap就是一个文件,里面储存着位置信息。
2020/06/06 09:25
vue提供的handleError句柄
2020/06/06 09:26
Error Boundary 标签
2020/06/06 09:26