10

编写代码只是做好项目的一小部分,写代码难免会碰到错误。因此,在项目上线后,我们还需要主动对项目的错误进行收集,不能等用户发现错误,再联系我们,我们再去处理。这样很容易造成大的损失,提前做好错误收集和处理,可以减少损失。

本人并没有做过相关的工作,下面的文章只是我在学习中的一点思考和总结,可能有比较多不足和错误的地方,希望大家指正和指导。

本文章为前端进阶系列的一部分,
欢迎关注和star本博客或是关注我的github

收集哪些错误信息

先从一个面试题开始吧。腾讯第二轮电话面试的一个题目:如果用户使用网页,发现白屏,现在联系上了你们,你们会向他询问什么信息呢?

<!-- more -->
一个个去堆答案没有意思,我们换个思路,先想一下为什么会白屏?

错误发生在什么环节

跟我之前的性能优化的文章一样,我们以用户访问页面的过程为顺序,大致排查一下

  1. 用户没打开网络
  2. DNS域名劫持
  3. http劫持
  4. cdn或是其他资源文件访问出错
  5. 服务器错误
  6. 前端代码错误
  7. 前端兼容性问题
  8. 用户操作出错

收集哪些信息

通过以上可能发生错误的环节,我们需要向用户手机一下以下的用户信息

  1. 当前的网络状态
  2. 运营商
  3. 地理位置
  4. 访问时间
  5. 客户端的版本(如果是通过客户端访问)
  6. 系统版本
  7. 浏览器信息
  8. 设备分辨率
  9. 页面的来源
  10. 用户的账号信息
  11. 通过performance API收集用户各个页面访问流程所消耗的时间,看错误出现在什么环节
  12. 收集用户js代码报错的信息

如何收集错误的信息

现在话题来到了如何收集错误信息了。

前端错误收集有两大流派:

一个是虚拟机监控,优点是指标齐全,并且可以进行竞品监控,缺点是反映不全,容易失真

另一个是脚本监控,优点是可以收集海量真实数据,缺点是影响性能,采样少的情况下容易失真。

这里暂时只讲脚本监控(挖个坑,之后可能填)

访问时间记录

performance API

在chrome浏览器控制台输入Performance.timing,会得到记录了一个浏览器访问各阶段的时间的对象。

进行错误收集的时候,可以对比这些时间,看错误发生在什么阶段

  1. DNS 查询耗时 :domainLookupEnd - domainLookupStart
  2. TCP 链接耗时 :connectEnd - connectStart
  3. request 请求耗时 :responseEnd - responseStart
  4. 解析 dom 树耗时 : domComplete - domInteractive
  5. 白屏时间 :responseStart - navigationStart
  6. domready 时间 :domContentLoadedEventEnd - navigationStart
  7. onload 时间 :loadEventEnd – navigationStart

其他方法

记录访问开始的时间可有以下的方法:

  1. 服务器将访问的时间渲染到页面上
  2. SPA的话,记录前一个页面卸载的时间

记录访问过程的时间

  1. 在head标签解析后,渲染body标签前加入script标签进行打点,一般将这个时间视为白屏时间
  2. 捕获DOMContentLoaded事件来记录dom元素加载完毕的时间
  3. 在首屏页面的所有图片加载完后进行记录,保存首屏时间
  4. 捕获load事件记录页面加载完成的时间

脚本错误收集

window.onerror

window.onerror可以捕捉运行时错误,可以拿到出错的信息,堆栈,出错的文件、行号、列号

要注意以下几点:

  1. 要把window.onerror这个代码块分离出去,并且比其他脚本先执行(注意这个前提!)即可捕捉到语法错误。
  2. 由于网络请求异常事件不会冒泡,需要在捕获阶段进行处理
  3. 不能捕获promise的错误信息
  4. 跨域资源需要专门处理,需要在script标签加上crossorigin属性,服务器设置Access-Control-Allow-Origin
  5. window.onerror 函数只有在返回 true 的时候,异常才不会向上抛出,否则即使是知道异常的发生控制台还是会显示 Uncaught Error: xxxxx。

promise的错误处理

promise除了使用catch方法来捕获错误,还可以使用window的unhandledrejection事件捕获异常的

window.addEventListener("unhandledrejection", function(e){
  // Event新增属性
  // @prop {Promise} promise - 状态为rejected的Promise实例
  // @prop {String|Object} reason - 异常信息或rejected的内容

  // 会阻止异常继续抛出,不让Uncaught(in promise) Error产生
  e.preventDefault()
})

try catch

无法捕捉到语法错误,只能捕捉运行时错误;
可以拿到出错的信息,堆栈,出错的文件、行号、列号; 需要借助工具把所有的function块以及文件块加入try,catch,可以在这个阶段打入更多的静态信息。

要注意的是try catch只能捕获同步代码的异常,对回调,setTimeout,promise等无能为力

上报错误的方式

  1. 后端提供接口,前端ajax上传
  2. 创建一个新的图片,url参数带上错误信息
function report(error) {
  var reportUrl = 'http://xxxx/report';
  new Image().src = reportUrl + 'error=' + error;
}

最后

本文章为前端进阶系列的一部分,
欢迎关注和star本博客或是关注我的github

参考

  1. 前端魔法堂——异常不仅仅是try/catch
  2. 前端优化-如何计算白屏和首屏时间

hpoenixf
534 声望95 粉丝

[链接]