Make the Web Fast!
王钰@wy-ei
---- 浅谈 Web 性能优化背景知识与技巧
HTML
CSS
DOM
CSSOM
Render Tree
Layout
Paint
Network
JavaScript
主题脉络
关键路径渲染
关键路径
HTML
CSS
DOM
CSSOM
Render Tree
Layout
Paint
Network
JavaScript
如果你不清楚什么是 CSSOM
p
span
font-weight: blod;
root
display: none;
从一个简单的例子开始
<!doctype html>�<meta charset=utf-8>�<title>Performance!</title>��<link href=styles.css rel=stylesheet />��<p>Hello <span>world!</span></p>
p { font-weight: bold; }
span { display: none; }
Index.html
styles.css
不能再简单了
HTML 正在传输......
<!doctype html>�<meta charset=utf-8>�<title>Performance!</title>��<link href=styles.css rel=stylesheet />��<p>Hello <span>world!</span></p>
p { font-weight: bold; }
span { display: none; }
index.html
styles.css
HTML
CSS
DOM
CSSOM
Render Tree
Network
DOM 树构建过程
图片来源于:developer.google.com
继续解析 HTML …...
<!doctype html>�<meta charset=utf-8>�<title>Performance!</title>��<link href=styles.css rel=stylesheet />��<p>Hello <span>world!</span></p>
p { font-weight: bold; }
span { display: none; }
index.html
styles.css
HTML
CSS
DOM
CSSOM
Render Tree
Network
CSS 部分到达,等待 CSS 加载完成......
<!doctype html>�<meta charset=utf-8>�<title>Performance!</title>��<link href=styles.css rel=stylesheet />��<p>Hello <span>world!</span></p>
p { font-weight: bold; }
span { display: none; }
index.html
styles.css
HTML
CSS
DOM
CSSOM
Render Tree
Network
CSS 文档中后面的规则可能覆盖掉之前的,因此需要等待 CSS 全部下载,才会开始构建 CSSOM 树。
CSS 全部加载完成,可以开始构建 CSSOM 树
<!doctype html>�<meta charset=utf-8>�<title>Performance!</title>��<link href=styles.css rel=stylesheet />��<p>Hello <span>world!</span></p>
p { font-weight: bold; }
span { display: none; }
index.html
styles.css
HTML
CSS
DOM
CSSOM
Render Tree
Network
依然空白,不要着急
Hello
P
world!
span
p
span
font-weight: blod;
root
display: none;
DOM 树
CSSOM 树
DOM + CSSOM = Render Tree (渲染树)
body
Hello
p
font-weight: blod;
渲染树
+
DOM + CSSOM = Render Tree (渲染树)
Hello
p
world!
span
p
span
font-weight: blod;
root
display: none;
CSSOM 树
DOM 树
body
body
HTML
CSS
DOM
CSSOM
Render Tree
Layout
Paint
Network
JavaScript
We are here!
<div style="width: 80%">
<h1>Performance</h1>
<p>Hello <span>world!</span></p>
</div>
layout(布局)
Performance
Hello
world!
Paint(绘制)
Performance
Hello
world!
Performance
Hello world!
layout:
pixels:
Paint(绘制)
Performance
Hello world!
viewport:
Performance
Hello world!
Tools:Chrome Tools > Setting > More tools > Rendering > Layer Borders
GPU 完成图层的合并
GPU
图层合并
渲染树
Hello
多个图层
终于!
Hello
HTML
CSS
DOM
CSSOM
Render Tree
Layout
Paint
Network
JavaScript
实际过程远比这复杂,但大体上看,基本就是这样。
等等,好像遗漏了什么?
JavaScript 呢?
引入 JavaScript
<!doctype html>�<meta charset=utf-8>�<title>Performance!</title>��<link href=styles.css rel=stylesheet />�<script src=app.js></script>
�<p>Hello <span>world!</span></p>
p { font-weight: bold; }
span { display: none; }
index.html
styles.css
Network
HTML
DOM
CSS
CSSOM
JavaScript
elem.style.width = "300px"
JavaScript 会动态改变 CSSOM 树
var width = elem.style.width;�elem.style.width = "300px";
document.write("I am cool !");
app.js
JavaScript 会动态改变 DOM 树
var width = elem.style.width;�elem.style.width = "300px";
document.write("I am cool !");
app.js
Why?比如,document.write 能够向文档中插入内容。
HTML
CSS
DOM
CSSOM
Render Tree
Layout
Paint
Network
JavaScript
一些准则(Rule)
工具
补充阅读
提升交互性能
性能 = 60 FPS.
1000 ms / 60 FPS = 16.6 ms / frame
FPS(frames per second),每秒刷新屏幕的次数。
首屏渲染性能
交互性能
HTML
CSS
DOM
CSSOM
Render Tree
Layout
Paint
Network
JavaScript
若 DOM 树或 CSSOM 树被改变,浏览器需要进行后续多个步骤
<10ms
frame
...
Javascript
更新渲染树
重排
重绘
合并图层
1000 / 60 = 16.6 ms
一帧又一帧
frame
frame
frame
frame
frame
frame
并非每一帧都要经过以上步骤,某些步骤可以跳过。
frame
超出 16ms 呢?
Javascript
frame
...
frame
frame
frame
frame
frame
重排
重绘
合并图层
26.5 ms
哥,等等我
更新渲染树
重排:重新计算 width/height 等涉及尺寸的属性
何时发生重排:
frame
避免强制性同步布局
强制性同步布局
frame
...
frame
frame
frame
frame
frame
重排
重绘
合并图层
...
for (n in nodes) {
let offsetLeft = n.offsetLeft;
n.style.left = offsetLeft + 1 + "px";
}
惰性重排
强制性同步布局会造成极大的性能问题
一帧内,多次重新计算样式(Recalculate Style)和 布局(Layout)
重绘:重新绘制图层
注意:重绘比较昂贵,尤其是手持设备。另手持设备的计算能力,可能不及 MBP 的 1/20,在调试时,可以模拟降低 CPU 性能的情况。
何时发生重绘:
并非每一帧都需要进行以下全部操作
Javascript
更新渲染树
重排
重绘
合并图层
可跳过
某些属性的改变,GPU 可以经过变换就能得到新的图层,无需重排、重绘。
硬件加速 101
视频来源:http://v.youku.com/v_show/id_XNjY3MTY4NjAw.html
CPU 和 GPU 绘图的对比
CPU
GPU
GPU 完成图层的变换
GPU
skew(30deg)
DEMO: 利用硬件加速构建流程动画
transform:skew(30deg)
关于图层
避免误用 transform: translateZ(0);
fixed 定位元素在滚动时引起整个页面重绘
滚动后定位元素相对于整个文档的位置变了,为获得新的页面,需要重绘整个页面。
解决方案:
使用 transform: translateZ(0); 将 fixed 定位元素提升至单独图层。
注:Chrome 在 dpi 较高的屏幕上会自动将 fixed 定位的元素提升至单独的图层,在 dpi 较低的屏幕上不会提升,另前端工程师常常使用 MacBook Pro。
免费的晚餐
使用 transform 完成动画
使用 opacity 来完成动画
是时候总结一下了
优化关键路径
提升交互性能
合理地利用硬件加速
唯一永远不改变,是不停的改变
规则会变,不可死守,耳听为虚,眼见为实
Question?