编写代码只是做好项目的一小部分,写代码难免会碰到错误。因此,在项目上线后,我们还需要主动对项目的错误进行收集,不能等用户发现错误,再联系我们,我们再去处理。这样很容易造成大的损失,提前做好错误收集和处理,可以减少损失。
本人并没有做过相关的工作,下面的文章只是我在学习中的一点思考和总结,可能有比较多不足和错误的地方,希望大家指正和指导。
本文章为前端进阶系列的一部分,
欢迎关注和star本博客或是关注我的github
收集哪些错误信息
先从一个面试题开始吧。腾讯第二轮电话面试的一个题目:如果用户使用网页,发现白屏,现在联系上了你们,你们会向他询问什么信息呢?
<!-- more -->
一个个去堆答案没有意思,我们换个思路,先想一下为什么会白屏?
错误发生在什么环节
跟我之前的性能优化的文章一样,我们以用户访问页面的过程为顺序,大致排查一下
- 用户没打开网络
- DNS域名劫持
- http劫持
- cdn或是其他资源文件访问出错
- 服务器错误
- 前端代码错误
- 前端兼容性问题
- 用户操作出错
收集哪些信息
通过以上可能发生错误的环节,我们需要向用户手机一下以下的用户信息
- 当前的网络状态
- 运营商
- 地理位置
- 访问时间
- 客户端的版本(如果是通过客户端访问)
- 系统版本
- 浏览器信息
- 设备分辨率
- 页面的来源
- 用户的账号信息
- 通过performance API收集用户各个页面访问流程所消耗的时间,看错误出现在什么环节
- 收集用户js代码报错的信息
如何收集错误的信息
现在话题来到了如何收集错误信息了。
前端错误收集有两大流派:
一个是虚拟机监控,优点是指标齐全,并且可以进行竞品监控,缺点是反映不全,容易失真
另一个是脚本监控,优点是可以收集海量真实数据,缺点是影响性能,采样少的情况下容易失真。
这里暂时只讲脚本监控(挖个坑,之后可能填)
访问时间记录
performance API
在chrome浏览器控制台输入Performance.timing,会得到记录了一个浏览器访问各阶段的时间的对象。
进行错误收集的时候,可以对比这些时间,看错误发生在什么阶段
- DNS 查询耗时 :domainLookupEnd - domainLookupStart
- TCP 链接耗时 :connectEnd - connectStart
- request 请求耗时 :responseEnd - responseStart
- 解析 dom 树耗时 : domComplete - domInteractive
- 白屏时间 :responseStart - navigationStart
- domready 时间 :domContentLoadedEventEnd - navigationStart
- onload 时间 :loadEventEnd – navigationStart
其他方法
记录访问开始的时间可有以下的方法:
- 服务器将访问的时间渲染到页面上
- SPA的话,记录前一个页面卸载的时间
记录访问过程的时间
- 在head标签解析后,渲染body标签前加入script标签进行打点,一般将这个时间视为白屏时间
- 捕获DOMContentLoaded事件来记录dom元素加载完毕的时间
- 在首屏页面的所有图片加载完后进行记录,保存首屏时间
- 捕获load事件记录页面加载完成的时间
脚本错误收集
window.onerror
window.onerror可以捕捉运行时错误,可以拿到出错的信息,堆栈,出错的文件、行号、列号
要注意以下几点:
- 要把window.onerror这个代码块分离出去,并且比其他脚本先执行(注意这个前提!)即可捕捉到语法错误。
- 由于网络请求异常事件不会冒泡,需要在捕获阶段进行处理
- 不能捕获promise的错误信息
- 跨域资源需要专门处理,需要在script标签加上crossorigin属性,服务器设置Access-Control-Allow-Origin
- 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等无能为力
上报错误的方式
- 后端提供接口,前端ajax上传
- 创建一个新的图片,url参数带上错误信息
function report(error) {
var reportUrl = 'http://xxxx/report';
new Image().src = reportUrl + 'error=' + error;
}
最后
本文章为前端进阶系列的一部分,
欢迎关注和star本博客或是关注我的github
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。