前端性能优化
- 实时性指标
- 可控时延
- 不可控时延
RAIL模型
响应(Response)
- 在50毫秒内处理用户输入事件, 对于需要超过50毫秒才能完成的操作,需要提供反馈
动画(Animation)
当动画的帧率是 >= 60帧/秒 的时候,人眼才不会觉得卡顿。此时的理论值为 1000毫秒/60帧 = 16.6 毫秒/帧
浏览器需要大约6毫秒的时间来渲染每一帧,所以,每一帧的准则建议是10毫秒
空闲时间(Idle Time)
最大化闲置时间,增加页面在50毫秒内响应用户输入的几率
加载(Loading)
目标在5秒或更短的时间内加载、解析、渲染,并确保用户可以交互
性能测量
DevTools 网络
- 右键可以保存为请求为 [har](https://zh.wikipedia.org/wiki/.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;
元素可见性检测
- [Intersection Observer API](https://developer.mozilla.org/zh-CN/docs/Web/API/Intersection_Observer_API)
相较于 Element.getBoundingClientRect() , 后者是在主线程上运行,因此频繁触发、调用可能会造成性能问题
- Profile
- 浏览器自带
- 页面埋点计时
- 资源加载时序图
优化全过程
静态资源优化
- 图片、资源文件的压缩合并等
优化图片 LCP 时间:
- 避免在浏览器视口使用大尺寸图片
- 减少浏览器视口的最大内容块区域,以减少下载和渲染时间
- 预加载
长任务优化
- 通过 setTimeout 把长任务拆分成多个宏任务
- 通过 Promise 的回调函数把长任务拆分为微任务
- 通过 requestAnimationFrame 拆分为微任务
- 使用 requestIdleCallback 在空闲时间执行长任务
- 使用 scheudler 决定任务运行时的优先级
页面渲染技术方案选型
- [前后端分离](/软件工程/架构/Web前端/前后端分离.html)
- SPA
- PWA
原生 混合开发优化
- 静态资源缓存代理离线技术
- 跨平台等
服务端网络优化
- CDN
- DNS
- 压缩
- HTTPS
- HTTP2
前端全链路监控
渲染优化
布局防抖
- 使用虚拟DOM减少、避免重排
- FastDom
事件防抖
- 使用节流或者防抖等方式降低事件触发频率
绘制
当DOM或CSS发生改动后,就会触发绘制
白屏优化
- 使用 PWA,使得可以缓存一些静态资源在本地
- hybrid 应用宿主可以缓存 HTML 在本地
FCP与FP优化
- 减少资源的加载时间
- 减少资源大小
- 预加载
- HTTP缓存
- 避免自定义字体
布局偏移优化
元素偏移的位置距离越远,布局偏移值就越大;影响视口面积越大,其影响比例也就越高,布局偏移值也就越大。CLS 值越小,用户体验越好。
一些常见的布局偏移原因:
- 异步加载图片,图片没有初始宽高,导致布局发生抖动
- 动态插入的内容,如广告
- 动画导致的布局抖动
- 自定义字体导致加载字体时的字体闪烁
静态资源优化
图片
- 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的执行
- 脚本位置:位于开头会阻塞页面渲染
- 合并脚本
- 异步脚本 (`