编写代码只是做好项目的一小部分, 写代码难免会碰到错误没. 因此, 在项目上线后, 我们还需要主动对项目的错误进行收集, 不能等用户发现错误, 再联系我们, 我们再去处理. 这样很容易造成大的损失, 提前做好错误收集和处理, 可以减少损失.
本人并没有做过相关的工作, 下面的文章只是我在学习中的一点思考和总结, 可能有比较多不足和错误的地方, 希望大家指正和指导.
本文章为前端进阶系列 http://hpoenixf.com/前端进阶系列-目录.html 的一部分,
收集哪些错误信息
先从一个面试题开始吧. 腾讯第二轮电话面试的一个题目: 如果用户使用网页, 发现白屏, 现在联系上了你们, 你们会向他询问什么信息呢?
一个个去堆答案没有意思, 我们换个思路, 先想一下为什么会白屏?
错误发生在什么环节
跟我之前的性能优化的文章 http://hpoenixf.com/web性能优化(一).html 一样, 我们以用户访问页面的过程为顺序, 大致排查一下
用户没打开网络
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;
- }
最后
本文章为前端进阶系列 http://hpoenixf.com/前端进阶系列-目录.html 的一部分,
来源: https://juejin.im/entry/5ac471936fb9a028c3690079