前端性能杂谈
Arthas Zheng
- Pinterest 的搜索引擎流量和注册人数增长 15%,得益于其感知等待时间减少 40%。
- COOK 的转化率提升 7%、跳出率下降 7%,且每次会话浏览页数增加 10%,得益于其页面平均加载时间减少 850 毫秒。
- BBC 发现其网站的加载时间每增加一秒,便会多失去 10% 的用户。
- DoubleClick by Google 发现,如果页面加载时间超过 3 秒,53% 的移动网站访问活动将遭到抛弃。
如何评估性能
RAIL标准

在 100 毫秒以内响应
在 10 毫秒内生成一帧
最大程度增加空闲时间
在 1000 毫秒以内呈现内容
Response - 在 100ms 内响应
延迟 | 用户反映 |
---|---|
0~16ms | 流畅 |
0~100ms | 感觉操作立即反馈 |
100~300ms | 轻微延迟 |
300~1000ms | 感觉到正在加载 |
1000+ms | 转移注意力 |
10000ms | 失望,放弃 |
Animation - 在 10ms 内生成一帧

预算:16ms
执行时间:10ms
Idle - 最大程度增加空闲时间
减少 long task,任务分块,保证单个任务小于执行时间 50ms。
Load - 1000ms 内呈现内容


建立以用户为中心的性能指标
- 性能数据需来源于真实用户
- 性能评估要基于真实用户体验
性能数据需来源于真实用户

性能评估需基于真实用户体验

如何准确地衡量用户真实感受到的性能?
性能监控
指标 |
---|
FP(First Paint) |
FCP(First Contentful Paint) |
FMP(First Meaningful Paint) |
TTI(Time to Interactive) |
First CPU Idle |
DOMContentLoaded |
onLoad |
Longtask 跟踪 |
输入延迟跟踪 |
... ... |
- 本地性能指标
- 用户性能指标
本地性能指标

- 页面总大小
- 请求总数
- 是否开启压缩
- 图片格式
- 是否懒加载
- 缓存
- ... ...
用户性能指标
performance.timings

const t = window.performance.timing;
const times = {};
// 【重要】页面加载完成的时间
// 【原因】这几乎代表了用户等待页面可用的时间
times.loadPage = t.loadEventEnd - t.navigationStart;
// 【重要】解析 DOM 树结构的时间
// 【原因】反省下你的 DOM 树嵌套是不是太多了!
times.domReady = t.domComplete - t.responseEnd;
// 【重要】重定向的时间
// 【原因】拒绝重定向!比如,http://example.com/ 就不该写成 http://example.com
times.redirect = t.redirectEnd - t.redirectStart;
// 【重要】DNS 查询时间
// 【原因】DNS 预加载做了么?页面内是不是使用了太多不同的域名导致域名查询的时间太长?
// 可使用 HTML5 Prefetch 预查询 DNS ,见:[HTML5 prefetch](http://segmentfault.com/a/1190000000633364)
times.lookupDomain = t.domainLookupEnd - t.domainLookupStart;
// 【重要】读取页面第一个字节的时间
// 【原因】这可以理解为用户拿到你的资源占用的时间,加异地机房了么,加CDN 处理了么?加带宽了么?加 CPU 运算速度了么?
// TTFB 即 Time To First Byte 的意思
// 维基百科:https://en.wikipedia.org/wiki/Time_To_First_Byte
times.ttfb = t.responseStart - t.requestStart;
// 【重要】内容加载完成的时间
// 【原因】页面内容经过 gzip 压缩了么,静态资源 css/js 等压缩了么?
times.request = t.responseEnd - t.requestStart;
// 【重要】执行 onload 回调函数的时间
// 【原因】是否太多不必要的操作都放到 onload 回调函数里执行了,考虑过延迟加载、按需加载的策略么?
times.loadEvent = t.loadEventEnd - t.loadEventStart;
// 【重要】白屏时间
times.blankTime = (t.domInteractive || t.domLoading) - t.fetchStart;
// DNS 缓存时间
times.appcache = t.domainLookupStart - t.fetchStart;
// 浏览器卸载前一个页面(同一个域下)的时间
times.unloadEvent = t.unloadEventEnd - t.unloadEventStart;
// TCP 建立连接完成握手的时间
times.connect = t.connectEnd - t.connectStart;
performance.getEntities()


接口/js/link/图片平均响应时间、慢接口/js/link/图片、FP/FCP...
performance.getEntities()都能做些什么?

同源限制
- 跨域只有部分数据
- 设置 "timing-allow-origin" 响应头的资源也算同源



duration包括阻塞时间


缓存相关
其他重要属性
TTI(Time to Interactive)
const ttiPolyfill = require('tti-polyfill');
const tti = await ttiPolyfill.getFirstConsistentlyInteractive();

First CPU Idle
const arr = performance.getEntriesByType('paint');
let data = {};
arr.forEach(item=>{data[item.name] = item.startTime});
- 当页面被最小化,或者其他方式隐藏时,浏览器没有绘制,取不到值
- duration始终为0
- navigation最为起始时间,也就是说 fp/fcp 的 startTime 是相对于performance.getEntriesByType('navigation').startTime的时间

FP/FCP
FP(first paint):首次绘制,第一次看到白屏的时间
FCP(first contentful paint):首次内容绘制,元素首次绘制的时间点
Long task(实验性)
const observer = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
// 上报
}
});
observer.observe({entryTypes: ['longtask']});
执行时间 >= 50ms 的任务

二娃
前端性能监控 sdk,基于神策
// npm install erwa --save --registry=https://npm.firstleap.cn
import Erwa from 'erwa';
// 传入项目名称
const erwa = new Erwa('LeapFlow', {
urlReg: /^https?:\/\/leapflow.firstleap.cn/
});
性能优化
- 加载优化
- 渲染优化
加载优化-减小代码体积
- 源码压缩
- gzip
- 按需加载、code split
- 移除未使用的代码、tree shaking
加载优化-缓存
- http缓存
- 本地缓存
- Service Worker
- CDN
加载优化-图片
- 压缩,裁剪
- 有损压缩
- 无损压缩
- 精灵图
- 预加载
- 视频替换gif
- 延迟加载
- CDN
-
选取合适格式的图片
- svg
- webp
- Baseline JPEG、Progressive JPEG


<picture>
<source
srcset="https://file-aliyun.firstleap.cn/test.png?x-oss-process=image/format,webp"
type="image/webp">
<img src="https://file-aliyun.firstleap.cn/test.png" alt="">
</picture>
// 加载图片时
function load(src){
if(isSupportWebp){
// 加载webp
}else{
// 加载原图片
}
}
加载优化-其他
- 多域名
- 字体优化
- http/2
- ... ...
渲染优化
- 动画用requestAnimationFrame
- 耗时任务用web worker
- 避免频繁更改样式(class vs style)
- 避免重排,重绘
- 硬件加速
- 频繁操作用Debounce
避免性价比低的性能优化
Thanks
前端性能杂谈
By Qingxin Zheng
前端性能杂谈
前端性能杂谈
- 2,898