奇技淫巧-获取JS所有error对象中的行、列

背景

最近在做前端监控,其中对JS错误需要上报:错误消息、错误文件、行、列、错误栈。需要通过上报的错误文件、行、列进行源代码的还原。

面临的挑战

乍一听,感觉也没什么,思路已经在脑海中:
1、window.onerror捕获事件队列中的错误
2、window.onunhandledrejection捕获没有catch的Promise报错
3、,通过script标签设置跨域属性来捕获跨域错误
4、React通过componentDidCatch捕获子组件的错误信息
5、Vue.config.errHandler获取vue项目的error对象
通过以上方法获取错误文件、行、列,再通过source-map还原源代码。
想法很美好,我们的业务主要是Vue框架,errorHandler用法如下

Vue.config.errorHandler = function (err, vm, info) {
  // handle error
}

Vue通过try{}catch(err){}获取错误,然后把catch得到的err对象传递给errorHandler。
问题来了,catch中的error对象是没有行、列信息的,测试打印如下

(function foo() {
    try {
        aa.bb
    } catch(err) {
        console.log(err)
    }
})()
VM327:5 ReferenceError: aa is not defined
    at foo (:3:9)
    at :7:3

只有错误消息和错误栈,没有行和列就还原不了源代码了。

思路

window.onerror有行和列信息,怎么让它接收所有错误呢?

window.onerror = function(message, file, line, col, error) { ... }

在同步JS中,throw err,可被window.onerror捕获,如下:
行、列

顺着这个思路,在Vue的errorHandler中把错误对象抛出,被window.onerror捕获,这样就能得到错误的行、列。
对errorhandler改造如下:

window.Vue.config.errorHandler = function (err) {
    throw err;
}

但是报错没有进入window.onerror并打印


捕获Vue报错

这时查看Vue源码得知,直接在errorHandler抛出错误会被Vue的try...catch捕获。那我们需要改造下代码如下:

window.Vue.config.errorHandler = function (err) {
    setTimeout(() => {
        throw err;
    })
}

通过setTimeout把错误在下一个宏任务抛出,这时就能被window.onerror捕获了,如下图:


捕获Vue报错

总结

JS错误需要上报错误文件、行、列信息的场景,都可以通过throw error的方式,被window.onerror接收然后解析出行、列信息,为还原源代码提供必要参数。

你可能感兴趣的:(奇技淫巧-获取JS所有error对象中的行、列)