如何优雅地查看 JS 错误堆栈?
本文由云+社区发表
在前端,我们经常会通过 window.onerror
事件来捕获未处理的异常。假设捕获了一个异常,上报的堆栈是这个:
typeerror: cannot read property 'module' of undefined at object.exec (https://my.cdn.com/dest/app.efe91e855d7432e402545e7d6c25d2d9.js:16:29828) at htmllielement.<anonymous> (https://my.cdn.com/dest/app.efe91e855d7432e402545e7d6c25d2d9.js:25:6409) at htmldivelement.dispatch (https://my.cdn.com/dest/vendor.eb28ded1876760b8e90973c9f4813a2c.js:1:248887) at htmldivelement.y.handle (https://my.cdn.com/dest/vendor.eb28ded1876760b8e90973c9f4813a2c.js:1:245631)
这个堆栈,你看得出问题来吗?我们发布到 cdn 的脚本文件,普遍是经过 uglifyjs 压缩的,所以堆栈可读性相当的差。假如有下面的一个堆栈查看工具,又如何?
堆栈查看工具
眼尖的同学,一眼就能找到问题。这里的 p[e]
出现了可能为 undefined
的情况。
这样一个工具,大大提高了问题定位的效率。
好,这里不卖瓜,我们来看下这当中的实现原理。
堆栈工具实现原理
一步步来说的话:
-
拿到原始堆栈字符串,使用
error-stack-parser
解析为堆栈帧,每个堆栈帧包含三个最重要的字段:
-
url
- 源码的 url 地址 -
line
- 堆栈位置行号 -
col
- 堆栈位置列号
-
对于
url
,我们可以用于加载源码内容,得到source
source 使用 uglifyjs 反向美化成多行的代码
prettysource
,并且同时生成sourcemap
堆栈帧中的
line
和col
通过sourcemap
,得到美化后对应的prettyline
和prettycol
将
prettysource
、prettyline
、prettycol
给到 monaco editor 渲染,就可以得到上述截图的效果
说那么多,不如贴代码是吧:
var result = uglifyjs.minify(source, { output: { beautify: true }, sourcemap: { filename: 'pretty.js', url: 'pretty.js.map' } }); var code = result.code; var rawsourcemap = json.parse(result.map); var consumerpromise = new sourcemap.sourcemapconsumer(rawsourcemap); resolve( consumerpromise.then(function(consumer) { return { code: code, sourcemapconsumer: consumer } }) );
上面就是使用 uglifyjs 对压缩代码进行反向美化的核心代码。下面给出 sourcemap 的使用源码:
var code = result.code; var consumer = result.sourcemapconsumer; var position = consumer.generatedpositionfor({ source: '0', line: linenumber, column: columnnumber }); parent.postmessage({ event: 'js-prettify-callback', payload: { hash: payload.hash, result: 'success', prettysource: code, prettylinenumber: position.line, prettycolumnnumber: position.column + 1 } }, sourceorigin);
完整源码有兴趣的读者也可以下下来把玩把玩:
源码只包含堆栈解析的实现,ui 的实现不在本文的讨论之内,用 react 随便画一画就好了。
此文已由作者授权腾讯云+社区在各渠道发布
获取更多新鲜技术干货,可以关注我们
上一篇: 清朝最厉害的火器专家戴梓,可惜清朝没用好
下一篇: 三国里最搞笑的四句话,看到不经笑出声