这周学习了一波前端性能分析和前端报错上传,当一个项目完成时,UI炫酷功能强大,却卡在性能瓶颈,势必会令项目黯然失色。并且当项目上线之后,如果无法进行错误的有效收集和定位,势必会给排查bug造成很大的困难。
说起前端性能指标,基础的有白屏时间,首屏时间,用户可操作,总下载时间,这里说一下基本概念:
白屏时间: 指用户首次看到内容的时间,一般会在head标签起始和结束位置做埋点
首屏时间:出现在视窗内所有资源加载完毕的时间,加载页面时开始统计,统计首屏所有图片加载时间(绑定load事件统计),页面加载完后判断图片是否在首屏内,找出最慢的一张;页面如果存在iframe,也要判断它的加载时间;
用户可操作时间:默认可以统计domready时间,因为通常会在这时候绑定事件操作。对于使用了模块化异步加载的 JS 可以在代码中去主动标记重要 JS 的加载时间,这也是产品指标的统计方式。对于React而言,也就是componentDidMount。
总下载时间:默认可以统计onload时间,这样可以统计同步加载的资源全部加载完的耗时。如果页面中存在很多异步渲染,可以将异步渲染全部完成的时间作为总下载时间。对异步渲染的代码进行埋点,耗时最长的则为总下载时间。
可以使用window.performance监测以上性能
performance接口的常用计算:
DNS查询耗时 :domainLookupEnd - domainLookupStart
TCP链接耗时 :connectEnd - connectStart
request请求耗时 :responseEnd - responseStart
解析dom树耗时 : domComplete - domInteractive
白屏时间 :responseStart - navigationStart
domready时间(用户可操作时间节点) :domContentLoadedEventEnd - navigationStart
onload时间(总下载时间) :loadEventEnd - navigationStart
监控错误:前端的错误监控和上报有几个知识点
捕获错误的脚本要放置在最前面,确保可以收集到错误信息,以免被错误脚本报错阻碍
前端错误类型:
1. 资源加载失败,样式、图片、脚本文件的请求异常,比如文件或者图片加载404了
解决方法,使用window.addEventListener的捕获方式可以获取报错信息: "HttpError at " + (e.target.baseURI || location.href) + " outerHTML:" + e.target.outerHTML
2. js脚本异常,即控制台常见的Error信息
3. 检测HTML劫持,比如被运营商强行注入标签或脚本
4. 页面样式丢失,CSS 展现异常
window.addEventListener方法使用
window.addEventListener('error'), function(e) {}, true
异常的提示信息,会直接告诉你是什么异常。这是识别一个异常的最重要依据,即e.message中的信息;
JS 文件名:异常发生在那个文件中。是堆栈信息中最顶层的那个文件。即e.filename。
异常所在行、列:异常的具体位置。行信息各浏览器基本还是一致的,列信息的差别较大,仅供参考。
堆栈信息:异常信息发生的堆栈,也是函数调用的堆栈信息,每下一层都是上一层的运行环境。即e.error.stack。每一层都包含类型、文件、行、列信息。但是注意堆栈信息可能会比较多,可以根据需要截取上报。safari和firfox的e.error.stack中不包含以上1,2,3的信息,只有堆栈信息,而chrome和IE中都包含,此处需要做兼容处理。
发生异常的设备信息,可以从window.navigator中选取自己需要的信息,或者直接使用window.navigator.userAgent
前端异常捕获方法使用:
window.onerror()能捕获到的异常,当然如果用addEventListener无论冒泡还是捕获阶段也能捕获到该异常。
只有在window.onerror()中return true 错误信息才不会向上抛出,否则即使是知道异常的发生控制台还是会显示 Uncaught Error: xxxxx。
window.onerror()无法捕获网络错误,由于网络请求异常不会事件冒泡,因此必须在捕获阶段将其捕捉到才行,但是这种方式虽然可以捕捉到网络请求的异常,但是无法判断 HTTP 的状态是 404 还是其他比如 500 等等,所以还需要配合服务端日志才进行排查分析才可以
4.资源加载失败也就是网络错误的一种,即、
5.捕获到错误后,阻止错误在控制台展示,线上自行收集错误信息以防外人看到
window.addEventListener('error', (function(e) {
console.log("-----errorEvent----", e)
e.preventDefault() //这里换成 return false或return true均不行!
}), true);
window.onerror = function(msg, url, line, col, error) {
console.log("------errorInfo---",msg, url, line, col, error)
return true; //这里用return false不行!
}
关于Promise错误:有时候promise没有写catch语句,这个报错onerror并不能捕获,最好添加一个 Promise 全局异常捕获事件 unhandledrejection
window.addEventListener("unhandledrejection", function(e){
e.preventDefault()
console.log('我知道 promise 的错误了');
console.log(e.reason);
return true;
});
Promise.reject('promise error');
new Promise((resolve, reject) => {
reject('promise error');
});
new Promise((resolve) => {
resolve();
}).then(() => {
throw 'promise error'
});
父窗口的onerror事件是无法捕获其中iframe中的JS错误的
Scirpt error
这个就是跨域脚本的问题了,基于安全协议跨域脚本的报错无法接收到具体信息。因为线上的版本,经常做静态资源 CDN 化,这就会导致我们常访问的页面跟脚本文件来自不同的域名,这时候如果没有进行额外的配置,就会容易产生 Script error,解决办法如下:
一:静态资源请求需要加多一个Access-Control-Allow-Origin头部。
二:标签加上crossorigin属性