前端性能优化
- 实时性指标
- 可控时延
- 不可控时延
RAIL模型
响应(Response)
- 在50毫秒内处理用户输入事件, 对于需要超过50毫秒才能完成的操作,需要提供反馈
动画(Animation)
当动画的帧率是 >= 60帧/秒 的时候,人眼才不会觉得卡顿。此时的理论值为 1000毫秒/60帧 = 16.6 毫秒/帧
浏览器需要大约6毫秒的时间来渲染每一帧,所以,每一帧的准则建议是10毫秒
空闲时间(Idle Time)
最大化闲置时间,增加页面在50毫秒内响应用户输入的几率
加载(Loading)
目标在5秒或更短的时间内加载、解析、渲染,并确保用户可以交互
性能测量
DevTools 网络
- 右键可以保存为请求为 har格式 方便在其他机器或软件上查看请求详细信息
单条请求详情
- 排队阶段:图片、音频等非核心资源如果遇到TCP连接满了,正在被其他css、js核心资源占用时,就会进入排队
- HTTP2 已经没有每个域名最多维护 6 个 TCP 连接的限制了
- 总的优化原则就是减少关键资源个数,降低关键资源大小,降低关键资源的 RTT 次数
- Initial connection/SSL 阶段:包括了建立 TCP 连接所花费的时间;如果使用了 HTTPS,那么还需要一个额外的 SSL 握手时间
- equest sent 阶段:浏览器把从缓冲区的数据发送出去的时间
- 第一字节时间(TTFB)
帧率
ctrl + shift + p 开启帧率显示
Performance Timing API
- 浏览器内核自带的JS API
耗时计算
let timing = performance.getEntriesByType('navigation')[0];
timing.domInteractive - timing.fetchStart
DNS 解析耗时: domainLookupEnd - domainLookupStart
TCP 连接耗时: connectEnd - connectStart
SSL 安全连接耗时: connectEnd - secureConnectionStart
网络请求耗时 (TTFB): responseStart - requestStart
数据传输耗时: responseEnd - responseStart
DOM 解析耗时: domInteractive - responseEnd
资源加载耗时: loadEventStart - domContentLoadedEventEnd
First Byte时间: responseStart - domainLookupStart
白屏时间: responseEnd - fetchStart
首次可交互时间(TTI): domInteractive - fetchStart
DOM Ready 时间: domContentLoadEventEnd - fetchStart
页面完全加载时间: loadEventStart - fetchStart
http 头部大小: transferSize - encodedBodySize
重定向次数:performance.navigation.redirectCount
重定向耗时: redirectEnd - redirectStart
长任务观察
const observer = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
console.log(entry)
}
})
observer.observe({entryTypes: ['longtask']})
可见性状态监听
- visibilitychange | webkitvisibilitychange 事件
- document.hidden || document.webkitHidden 属性
网络状况监听
const connection = navigator.connection || navigator.mozConnection || navigator.webkitConnection;
connection.effectiveType;
元素可见性检测
相较于 Element.getBoundingClientRect() , 后者是在主线程上运行,因此频繁触发、调用可能会造成性能问题
- Profile
- 浏览器自带
- 页面埋点计时
- 资源加载时序图
优化全过程
静态资源优化
- 图片、资源文件的压缩合并等
页面渲染技术方案选型
- 前后端分离
- SPA
- PWA
原生 混合开发优化
- 静态资源缓存代理离线技术
- 跨平台等
服务端网络优化
- CDN
- DNS
- 压缩
- HTTPS
全链路监控
渲染优化
布局防抖
- 使用虚拟DOM减少、避免重排
- FastDom
事件防抖
- 使用节流或者防抖等方式降低事件触发频率
绘制
当DOM或CSS发生改动后,就会触发绘制
静态资源优化
图片
- png无损 有透明通道
- jpg有损
- web的压缩介于png与jpg之间
优化方法:
- 打包时对图片进行压缩
- 根据不同网络状况加载不同质量图片
- 懒加载
- 精灵图
- Web Font 、Data URI代替图片
HTML
- 精简字符
- CSS与JS的放置位置错误会阻塞影响页面的渲染
- 优化首屏加载的用户体验
CSS
- 渲染性能
- 避免深层级选择器
- 避免代价高的属性(费内存,费CPU、GPU)
- 避免代价高的选择器(expression表达式,正则表达式)
- 加载性能
- CDN
- @import会阻塞
- 精简字符
- 字体
- CDN
- 动画
- 避免同时过多动画
- 使用SVG替代
JavaScript
JavaScript 文件的下载过程会阻塞 DOM 解析
该把CSS放在文档的头部,尽可能的提前加载CSS;把JS放在文档的尾部,这样JS也不会阻塞页面的渲染。CSS会和JS并行解析,CSS解析也尽可能的不去阻塞JS的执行
- 脚本位置:位于开头会阻塞页面渲染
- 合并脚本
- 异步脚本 (
<script async>
)- async 下载完后立刻执行
- defer 会在等待dom加载完成后被触发
- 动态脚本(通过动态创建dom节点实现)
- 预解析
- DNS Prefetch
<meta http-equiv="x-dns-prefetch-control" content="on" />
- preload
<link rel="preload" href="/main.js" as="script">
- prefetchprefetch
<link href="main.js" rel="prefetch">
页面渲染优化
渲染方案
静态化方案
- 物理HTML文件 性能较高 服务器负载较低
- 需要考虑文件占用的磁盘空间及文件更新问题
前后端分离
- 前端负责实现页面前端交互,根据后端 API 接口拼装前端模板
SPA
- 使用js重写当前页面 达到不刷新页面重载页面的目的
BigPipe方案
- 通过将页面划分为不同独立的小块 加快传输渲染
同构直出
只开发一套项目代码,既可以实现前端的渲染,也可以做后台的直出, 所谓直出,指的是直接由服务端执行js返回渲染好的html内容
PWA
桌面端优化策略
网络:
- 减少HTTP请求次数及请求大小
- 使用外部文件引入css或者js可以利用浏览器缓存
- 避免空href和src 他们也会发起请求
- 合理利用HTTP缓存
- 减少重定向
- 增加静态域增加下载并行数
- 合理利用CDN
- 使用可缓存的AJAX
- 减少cookie大小
- 缓存favicon.ico
- 异步加载js资源
- 避免CSS或者js资源阻塞渲染
页面渲染:
- CSS放头部:优先下载完成渲染
- JS放底部:避免JS对页面渲染造成阻塞
- 避免在HTML直接缩放图片
- 减少DOM数量及深度
- 避免table iframe等慢元素
- 避免运行耗时过长的JS
- 避免CSS表达式或者滤镜
移动端优化策略
网络:
- 提前首屏数据请求 避免JS文件加载后才加载数据
- 首屏按需加载 展示延时不超过3秒
- 模块化资源并行下载
- 内联首屏必须的css及js
- dns预解析
- 资源预加载
- 合理利用MTU 1500B
缓存:
- 合理利用浏览器缓存
- 静态资源离线方案
- AMP HTML
图片:
- 对所有移动端的图片都需要压缩处理
- 使用较小的图片 合理利用BASE64内嵌图片
- 使用更高压缩比的格式 如webp
- 图片懒加载
- 利用CDN加载不同大小的图片
- 图标精良使用iconfont
- 限制图片最大大小
脚本:
- 使用ID选择器 其最快
- 缓存DOM对象
- 使用事件代理 避免直接事件绑定
- 使用touchstart代替click
- 避免touchmove scroll 连续事件代理 需要合理进行节流
- 避免eval with 推荐ES6模板字符串
- 推荐使用ES6规范
渲染:
- 使用viewport固定屏幕渲染
- 避免各种重排重绘
- 使用CSS3动画 开启GPU加速
- 使用canvas实现动画更高效
- 使用SVG代替图片
- 少用float 耗性能
- 避免过多的font-size声明
架构协议:
- 使用SPDY与HTTP2等新协议
- 后端数据渲染
- 使用NativeView代替传统DOM