如何优雅地查看 JS 错误堆栈?

qcloudcommunity · · 1249 次点击 · 开始浏览    置顶
这是一个创建于 的主题,其中的信息可能已经有所发展或是发生改变。

> 本文由云+社区发表 在前端,我们经常会通过 `window.onerror` 事件来捕获未处理的异常。假设捕获了一个异常,上报的堆栈是这个: ```js 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 压缩的,所以堆栈可读性相当的差。假如有下面的一个堆栈查看工具,又如何? ![img](https://ask.qcloudimg.com/draft/1000005/xnao781o7d.png?imageView2/2/w/1620)堆栈查看工具 眼尖的同学,一眼就能找到问题。这里的 `p[e]` 出现了可能为 `undefined` 的情况。 这样一个工具,大大提高了问题定位的效率。 好,这里不卖瓜,我们来看下这当中的实现原理。 ![img](https://ask.qcloudimg.com/draft/1000005/dbxd1i7goh.png?imageView2/2/w/1620)堆栈工具实现原理 一步步来说的话: - 拿到原始堆栈字符串,使用 error-stack-parser 解析为堆栈帧,每个堆栈帧包含三个最重要的字段: - `url` - 源码的 URL 地址 - `line` - 堆栈位置行号 - `col` - 堆栈位置列号 - 对于 `url`,我们可以用于加载源码内容,得到 `source` - source 使用 [UglifyJs](https://github.com/mishoo/UglifyJS2) 反向美化成多行的代码 `prettysource`,并且同时生成 `sourcemap` - 堆栈帧中的 `line` 和 `col` 通过 `sourcemap` [反查](https://github.com/mozilla/source-map#consuming-a-source-map),得到美化后对应的 `prettyline` 和 `prettycol` - 将 `prettysource`、`prettyline`、`prettycol` 给到 [Monaco Editor](https://microsoft.github.io/monaco-editor/) 渲染,就可以得到上述截图的效果 说那么多,不如贴代码是吧: ```js 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 的使用源码: ```js 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); ``` 完整源码有兴趣的读者也可以下下来把玩把玩: [js-loader.html.zip](https://ask8088-1251520898.file.myqcloud.com/draft/1000005/h7846jpv0c.zip) 源码只包含堆栈解析的实现,UI 的实现不在本文的讨论之内,用 React 随便画一画就好了。 **此文已由作者授权腾讯云+社区在各渠道发布** **获取更多新鲜技术干货,可以关注我们[腾讯云技术社区-云加社区官方号及知乎机构号](https://www.zhihu.com/org/teng-xun-yun-ji-zhu-she-qu/activities)**

有疑问加站长微信联系(非本文作者)

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

1249 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传