本文由云+社区发表在前端,我们经常会通过 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,我们可以用于加载源码内容,得到 sourcesource 使用 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);完整源码有兴趣的读者也可以下下来把玩把玩:js-loader.html.zip源码只包含堆栈解析的实现,UI 的实现不在本文的讨论之内,用 React 随便画一画就好了。此文已由作者授权腾讯云+社区在各渠道发布获取更多新鲜技术干货,可以关注我们腾讯云技术社区-云加社区官方号及知乎机构号