前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >前端异常捕获和定位

前端异常捕获和定位

作者头像
GopalFeng
发布2020-09-24 16:46:08
1.2K0
发布2020-09-24 16:46:08
举报

前言

于前端而言,不管是开发还是生产阶段,异常的捕获和定位都是至关重要的。

开发阶段,通过详细的报错信息,我们可以快速定位并解决问题。在生产,通过异常监控,根据异常埋点信息,我们可以第一时间知道异常信息,不至于造成严重后果。

window.onerror

全局监听异常来捕获

借鉴下 MDN 的说明,当 JavaScript 运行时错误(包括语法错误)发生时候, window 会触发一个 ErrorEvent 接口的 error 事件,并执行 window.onerror()。加载一个全局的 error 事件处理函数可用于自动收集错误报告。

语法:

代码语言:javascript
复制
window.onerror = function(message, source, lineno, colno, error) { ... }

参数说明:

  • message:错误信息(字符串)。可用于 HTML onerror=""处理程序中的event
  • source:发生错误的脚本 URL(字符串)
  • lineno:发生错误的行号(数字)
  • colno:发生错误的列号(数字)
  • error:Error 对象

若该函数返回 true,则阻止执行默认事件处理函数,也就是不会在控制台打印错误。

好的,我们通过一个实例解析下

直接上代码

代码语言:javascript
复制
<html>
  <head>
    <script type="text/javascript">
      onerror = handleErr;
      var txt = "";
      function handleErr(msg, source, lineno, colno, error) {
        txt = "There was an error on this page.\n\n";
        txt += "错误信息: " + msg + "\n";
        txt += "发生错误的脚本URL: " + source + "\n";
        txt += "发生错误的行数: " + lineno + "\n\n";
        txt += "发生错误的列数: " + colno + "\n\n";
        txt += "Click OK to continue.\n\n";
        alert(txt);
        return false;
      }
      function message() {
        adddlert("Welcome guest!");
      }
    </script>
  </head>

  <body>
    <input type="button" value="View message" onclick="message()" />
  </body>
</html>

点击 View message 的时候,就会显示如下弹窗

另外控制台会有报错,这是我们最后的 return false。假如 return true 是看不到相关的报错信息的

在 onerror 的回调函数中,我们发送相关的埋点信息(相关的报错信息,行数,列数等等)到我们的监控平台,就可以实现基础的页面监控了

try...catch...

try...catch...。其中 try 指定要运行的代码块,catch 指定该代码块运行错误时候,抛出的响应。

比如:

代码语言:javascript
复制
try {
  nonExistentFunction();
}
catch(error) {
  console.error(error);
  // expected output: ReferenceError: nonExistentFunction is not defined
  // Note - error messages will vary depending on browser
}

我们使用 try...catch... 最主要是不会因为一处报错,导致我们页面挂掉。在 catch 中我们也可以发送相关埋点到我们的监控平台。

关于 Vue 异常捕获

之所以会存在这种场景,是因为 Vue 自身已经通过 try...catch... 处理,而不会触发 window.onerror 事件,所以我们有时候也需要专门对 Vue 进行异常捕获

我们可以使用 Vue.config.errorHandler[1] 对 Vue 进行全局的异常捕获

指定组件的渲染和观察期间未捕获错误的处理函数。这个处理函数被调用时,可获取错误信息和 Vue 实例。在处理函数中,我们除了发送相关的埋点信息,可以在控制台打印一下相关的报错信息,注意默认这个捕获的方法是不会在控制台打印的,这对于我们开发来讲是不友好的

代码语言:javascript
复制
Vue.config.errorHandler = function (err, vm, info) {
  // handle error
  // `info` 是 Vue 特定的错误信息,比如错误所在的生命周期钩子
  // 只在 2.2.0+ 可用
}

关于跨域

加载来自不同域的脚本发生错误的时候,为了避免信息泄露,语法细节不会再上报,而是简单的 "Script error"

解决方法是,在 script 标签中使用 crossorigin 属性并要求服务器端发送适当的 CORS HTTP 响应头,则可以解决这个问题,也就是要求服务端设置 Access-Control-Allow-Origin

代码语言:javascript
复制
<script src="http://cdn.xxx.com/index.js" crossorigin="anonymous"></script>

在 webpack 中,我们可以设置 output 中 crossOriginLoading 为 anonymous,如下所示

代码语言:javascript
复制
output: {
    path: path.resolve(__dirname, '../dist'),
    filename: '[name].js',
    publicPath: '',
    chunkFilename: '[name].js',
    library: 'MST',
    crossOriginLoading: 'anonymous'
  }

关于 sourcemap

当我们使用 webpack 打包我们 Vue 应用的时候,最后生成的代码都是混淆过的,主要出于安全和性能两个方面的考虑。但是在我们开发阶段这样是不利于我们定位和调试问题的。所以我们可以开启 source map 模式。我们只需要配置 webpack 的 devtool 选项即可,详见webpack devtool 官网[2]。示例所示:

代码语言:javascript
复制
devtool: 'eval-source-map'

但是 sourcemap 很好用,但是生产上我们一般不能使用 sourcemap,主要还是安全方面的考虑,如果将 sourcemap 文件发布到线上,可能会造成代码泄露、业务流失、系统被攻击等等风险。那么线上的问题,我们怎么能够知道详细的异常信息呢?

介绍一个 sourcemap 调试线上问题的技巧 首先本地 webpack 打包依然生成 sourcemap 文件,但是我们不上传到服务器,只保留在本地服务器。当报错时候,我们使用 whistle 拦截和线上的 js 替换成我们本地 sourcemap 文件。这样就相当于加载我们本地的 sourmap 文件了。

关于异步的异常捕获

为什么 try...catch...不能捕获到异步的异常?

这个涉及到了事件循环(Event Loop)相关知识了,首先 js 是单线程的,当我们 try 中执行的代码是异步的时候,当异步执行报错时候,可能同步代码已经从执行栈中取出并执行完毕了,所以没有办法捕获到异步的异常

那我们应该如何捕获异步的异常呢?

  • 通过 Promise 的 catch 可以捕获到异常
代码语言:javascript
复制
// reject
const p1 = new Promise((reslove, reject) => {
  if(1) {
    reject();
  }
});
p1.catch((e) => console.log('p1 error'));
代码语言:javascript
复制
// throw new Error
const p2 = new Promise((reslove, reject) => {
  if(1) {
    throw new Error('p2 error')
  }
});

p2.catch((e) => console.log('p2 error'));

Promise 不管内部是 reject 还是 throw new Error,都可以通过 catch 捕获

  • 使用 async 和 await 时候捕获异常
代码语言:javascript
复制
run();
async function run() {
    try {
        await Promise.reject(new Error("Oops!"));
    } catch (error) {
        error.message; // "Oops!"
    }
}

参考

GlobalEventHandlers.onerror[3]

JS 拦截/捕捉 全局错误 全局 Error onerror[4]

【webpack】你所不知道的 sourceMap[5]

JS 异步错误捕获二三事[6]

[1]

Vue.config.errorHandler: https://cn.vuejs.org/v2/api/#errorHandler

[2]

webpack devtool 官网: https://webpack.js.org/configuration/devtool/

[3]

GlobalEventHandlers.onerror: https://developer.mozilla.org/zh-CN/docs/Web/API/GlobalEventHandlers/onerror

[4]

JS 拦截/捕捉 全局错误 全局Error onerror: https://cloud.tencent.com/developer/article/1155597

[5]

【webpack】你所不知道的sourceMap: https://juejin.im/post/5e099ee3f265da33910a547d

[6]

JS 异步错误捕获二三事: https://juejin.im/post/5cc15de5e51d456e68659340

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-01-15,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 前端杂货铺 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • window.onerror
  • try...catch...
  • 关于 Vue 异常捕获
  • 关于跨域
  • 关于 sourcemap
  • 关于异步的异常捕获
  • 参考
相关产品与服务
前端性能监控
前端性能监控(Real User Monitoring,RUM)是一站式前端监控解决方案,专注于 Web、小程序等场景监控。前端性能监控聚焦用户页面性能(页面测速,接口测速,CDN 测速等)和质量(JS 错误,Ajax 错误等),并且联动腾讯云应用性能监控实现前后端一体化监控。用户只需要安装 SDK 到自己的项目中,通过简单配置化,即可实现对用户页面质量的全方位守护,真正做到低成本使用和无侵入监控。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档