浏览器渲染流程与性能指标
🎨 性能优化的核心是缩短关键渲染路径、减少主线程工作,并围绕真实用户体验指标持续测量。
浏览器渲染流水线
- 解析 HTML,构建 DOM。
- 解析 CSS,构建 CSSOM。
- 合并 DOM 与 CSSOM,生成渲染树。
- Layout:计算元素几何位置与尺寸。
- Paint:生成绘制指令。
- Composite:合成图层并显示到屏幕。
JavaScript 可能阻塞 HTML 解析;样式表通常会阻塞渲染。defer 脚本在 HTML 解析完成后按顺序执行,async 下载完成即执行且顺序不确定。
重排、重绘与合成
- Layout / Reflow:几何信息改变,代价通常最高。
- Paint:外观改变但几何不变,例如颜色、阴影。
- Composite:合成层变换,例如合适场景下的
transform、opacity。
⚠️ 不要把“使用 transform”机械等同于“永远更快”。过多合成层会增加显存、上传和合成成本。
强制同步布局
在写入样式后立即读取布局属性,浏览器可能被迫提前计算布局:
// 容易反复触发布局
for (const item of items) {
item.style.width = `${item.offsetWidth + 1}px`
}
// 批量读,再批量写
const widths = items.map(item => item.offsetWidth)
items.forEach((item, i) => {
item.style.width = `${widths[i] + 1}px`
})
常见布局读取包括 offsetWidth、getBoundingClientRect()、getComputedStyle()。
Core Web Vitals
- LCP:最大内容绘制,反映主要内容加载速度;目标通常 ≤ 2.5 秒。
- INP:交互到下一次绘制,反映页面响应性;目标通常 ≤ 200 毫秒。
- CLS:累计布局偏移,反映视觉稳定性;目标通常 ≤ 0.1。
辅助指标:
- TTFB:首字节时间
- FCP:首次内容绘制
- TBT:总阻塞时间,常用于实验室环境
优化策略
加载
- 压缩资源并使用 HTTP 缓存、CDN。
- 关键资源预加载,非关键资源延迟加载。
- 图片提供正确尺寸、现代格式与
srcset。 - 拆分 JavaScript,减少首屏执行和第三方脚本。
运行时
- 拆分长任务,给输入和渲染让出主线程。
- 对大列表使用虚拟化。
- 避免无意义的重复渲染、布局抖动和频繁序列化。
- 将适合的计算移到 Web Worker。
稳定性
- 为图片、视频、广告预留尺寸。
- 避免在已有内容上方动态插入内容。
- 使用合适的字体加载策略。
测量工具
- Chrome DevTools Performance:主线程、火焰图、Layout 与 Paint。
- Lighthouse:实验室诊断。
- PerformanceObserver / web-vitals:真实用户监控。
- DevTools Network:资源瀑布、缓存和优先级。
new PerformanceObserver(list => {
for (const entry of list.getEntries()) {
console.log(entry.name, entry.duration)
}
}).observe({ type: 'longtask', buffered: true })
排查路径
- 明确是加载慢、交互卡顿还是视觉跳动。
- 用真实设备和弱网复现。
- 记录基线指标。
- 在时间线上定位瓶颈。
- 一次只验证一个假设。
- 上线后通过真实用户数据观察回归。