Appearance
有哪些重要的性能的指标?
- FP: First Paint (首次渲染时长)
- FCP: First Contentful Paint (首次内容渲染时长/白屏时间)
- FMP: First Meaningful Paint (首次有效渲染时长/首屏时间)
- TTI: Time To Interactive (首次可交互时长)
- PLT: Page Load Time (页面加载时长)
参考资料:
性能优化策略
- 请求数量:合并脚本和样式表;CSS Sprites;拆分初始化负载,按需加载;划分主域等
- 请求带宽:开启 GZip;分包;精简 JavaScript,移除重复脚本;图像优化等
- 缓存利用:使用 CDN;使用外部 JavaScript 和 CSS;添加 Expires 头,配置 ETag;DNS 预解析,减少 DNS 查找;使 Ajax 可缓存等
- 页面结构:预加载;预渲染;将样式表放在顶部,将脚本放在底部,尽早刷新文档的输出
- 代码校验:避免 CSS 表达式;编写高效的 CSS 代码;避免重定向;节流&防抖
网络优化方向:
- 开启 HTTP2:首部压缩、多路复用、二进制格式传输信息
- 域名收敛:最大化节省 DNS 解析,TCP 建连等网络成本
- DNS 预解析:
<link rel="dns-prefetch" href="//xxx.cdn.com/">,比较适合 CDN 域名场景 - 提前建立网络连接:使用
preconnet的link标签提前触发 DNS 解析、TCP 握手、TLS 加密信息验证等操作。适合可以判断页面有极大可能使用的网络连接(如 Server API );对于 CDN 的资源,由于缓存的存在大多数情况并不会发送资源请求,所以不适合进行preconnet brotli压缩:谷歌在 2015 年发布 Brotli 压缩算法,相比 gzip,它具有更高的压缩比和更快的压缩性能- 支持 TLS 1.3:使用 TLS 1.3 协议只需要一次往返( 1-RTT )就可以完成握手,而使用 TLS 1.2 需要两次往返( 2-RTT )才能完成握手,然后才能发送请求。相比 TLS 1.2,TLS 1.3 的握手时间减半
- 支持 HSTS:
Strict-Transport-Security(简称HSTS)HTTP Header 会告知浏览器在和网站进行通信的时候强制性的使用 HTTPS,而不是通过明文的 HTTP 进行通信,注意是在浏览器端进行 HTTPS 重定向,这个会减少一次请求时间
参考资料:
如何达到 60fps?
- 避免没有必要的重排
- 避免没有必要的重绘
- 利用 GPU 加速渲染
- 构建更为流畅的动画
- 正确地处理滚动事件
结合浏览器渲染 Web 页面的过程来分析
参考资料:
页面 DOM 节点太多,会出现什么问题?如何优化?
前端需要渲染大量数据,这种情况下网页会出现掉帧、卡顿或假死等情况。
通常采用「虚拟列表」的方式来解决问题。
虚拟列表指的就是「可视区域渲染」的列表,重要的基本就是两个概念:
**可滚动区域:**假设有 1000 条数据,每个列表项的高度是 30,那么可滚动的区域的高度就是 1000 * 30。当用户改变列表的滚动条的当前滚动值的时候,会造成可见区域的内容的变更。
**可见区域:**比如列表的高度是 300,右侧有纵向滚动条可以滚动,那么视觉可见的区域就是可见区域。 实现虚拟列表就是处理滚动条滚动后的可见区域的变更,其中具体步骤如下:
- 计算当前可见区域起始数据的 startIndex
- 计算当前可见区域结束数据的 endIndex
- 计算当前可见区域的数据,并渲染到页面中
- 计算 startIndex 对应的数据在整个列表中的偏移位置 startOffset,并设置到列表上
如何做性能监控?
参考资料:
如何做前端错误监控?
监控:
- javascript 异常(语法错误、运行时错误、跨域脚本)
window.onerror捕获 js 异常- 跨域脚本异常:一般涉及跨域的 js 运行错误时会抛出错误提示
script error,但没有具体信息(如出错文件,行列号提示等),可利用资源共享策略来捕获跨域 js 错误(客户端:在 script 标签增加crossorigin="anonymous"属性;服务端:静态资源响应头Access-Control-Allow-Origin: *)
- 资源加载异常(js, css):利用
window.addEventListener('error', cb, true)捕获异常 - Ajax 请求异常:利用
xhr.onreadystatechange/xhr.onerror统一拦截处理 - Promise 异常 promise 中的报错顺序是:如果有
catch等捕获函数,则走catch捕获函数。catch捕获函数如果没有抛出新的异常,则下一个then将会认为没有什么报错,会继续执行。如果没有catch等捕获函数,我们需要注册window.addEventListener('unhandledrejection')来处理 - Vue 项目中全局异常捕获:利用
Vue.config.errorHandler = function (err, vm, info) { ... }捕获处理
上报:
js
function report (msg) {
var reportUrl = 'http://xxxx/report'
new Image().src = reportUrl + encodeURIComponent(JSON.stringify(msg))
}前端监控/数据埋点使用 1x1 像素透明 gif图片进行上报主要原因是:
- 没有跨域问题,一般这种上报数据,代码要写通用的;(排除 ajax)
- 不会阻塞页面加载,影响用户的体验,只要 new Image 对象就好了;(排 除 JS/CSS 文件资源方式上报)
- 在所有图片类型中,体积最小,避免过多资源损耗;(比较 PNG/JPG)
在页面 unload 时,如果要上报当前数据,采用 xhr 的同步上报方式,会阻塞当前页面的跳转;使用 new Image有可能遇到 aborted,导致无法成功发送。
参考资料:
一个请求包含哪些时间消耗?

- Resource Scheduling,资源调度
- Queueing: 请求任务调度排队耗时,浏览器同时处理很多请求,发送一个请求不是立即去发,是有一个调度过程的
- Connection Start,建立连接
- Stalled: 闲置时间,程序准备工作
- DNS Lookup: DNS 查询时间
- Initial connection: TCP 建立连接,3 次握手
- SSL: SSL 连接
- Request/Response,收发请求
- Request sent: 发请求
- Waiting (TTFB): 首字节返回等待
- Content Download: 下载
浏览器同时处理很多请求,不能说你想发一个请求,就立即帮你发;它其实有一个调度过程的,浏览器也不是无限制的发送请求,通常一个 TCP 发送 6 个。
