@yangfch3
2017-01-16T22:07:54.000000Z
字数 3108
阅读 3087
FE
HTML+CSS
JavaScript
一个页面的呈现需要经历
Parse HTML
) Evaluate Script
)Recalculate Style
)Layout
)Paint
)Composite
)这个过程又叫做关键呈现路径,关键呈现路径的每一步都是自变量,影响着最终页面呈现的耗时。而我们对页面呈现表现的优化的出发点也是上面的几个过程,尽量减少呈现路径每一步的耗时,以优化页面的表现。
同时借助上面总结的过程,我们也很容易分析我们在页面稳定后的一些操作带来的资源开销大小,比如有些操作会带来 DOM 树的改变、重新布局、重新绘制,有些操作则只会带来 CSSOM 树的改变、重新绘制。现在,我们也就很容易明白回流与重绘的差异,明白如何优化我们的操作从而减少资源的开销了。
上图很好地展示了从磁盘或网络中获取的 HTML 文档到最终的 DOM 树的整个过程。
构建 DOM 树在一些大型页面上的耗时较多,且很容易成为页面性能的瓶颈,在 Timeline 面板构建 DOM 树对应着 Parse HTML 事件(阶段)。
光有 DOM 树还是无法绘制得到我们看到的页面,我们还需要 CSSOM(CSS 对象模型)。CSSOM 构建“原料”的来源有:外部 CSS 文件(包括 import 的样式表)、内部 style 标签、内联样式(与标签写在一起)。
用户代理为每一个 HTML 元素准备了一套预设样式,我们的样式是对用户代理样式的覆盖。
正因为我们最终渲染绘制需要依赖 CSSOM,所以 CSSOM 的构建是阻塞渲染的。
构建 CSSOM 树在浏览器中的称呼是:Recalculate Style
叫做 Recalculate 是因为我们样式其实是在预设样式的基础上的重新计算。
CSSOM 树与 DOM 树融合成一棵 Render 树(渲染树),渲染树包括着渲染页面需要的节点。
包括渲染页面需要的节点的言外之意便是:并非包括所有的 DOM 节点,像 head, script, meta 这样的不可见节点,以及
display: none
的节点不会在 Render 树上出现。
有了 Render 树之后,就会进入布局阶段。
通过 Render 树我们能知道一个元素的表现是怎样的,但是我们还却一样东西:元素在页面何处?元素尺寸如何?这个就是布局阶段要做的了:计算位置尺寸。
一旦布局(Layout)步骤完成,浏览器便发布 “Paint Setup” 与 “Paint” 事件,执行 paint
操作,将 渲染树 + 布局信息 转化为屏幕上的实际像素。
在布局(layout)和绘制(paint)之后,浏览器会将多个复合层传入 GPU,进行合成工作(之前的布局与绘制都需要 CPU 的复杂计算)。
对于 JavaScript 动画带来的重新布局、重新绘制和重新合成及其优化请移步另外一篇文章。
既然我们已经知道了一个页面如何呈现,那么我们现在就来分析一下这些步骤里面那些可能带来流程的阻塞吧。
我们页面呈现的主线是 DOM 树的构建(Parse HTML),支线是 CSSOM 树的构建,同时还会有脚本的执行插入主线。一旦主线、支线汇合,形成 Render 树,便可顺利地布局、绘制。
因此,我们很容易得出初步的想法:以下这些因素影响着呈现的耗时
因为 JavaScript 代码可能会牵涉到元素样式的操作(读、写),所以 JavaScript 的执行又依赖脚本前面 CSSOM 树的构建完毕,也就是说 CSSOM 树的构建阻塞了 JavaScript 的立即执行
HTML 5 规范指出:
- 脚本执行前,出现在当前
<script>
之前的<link rel="stylesheet">
必须完全载入。- 脚本执行会阻塞DOM解析。
依赖阻塞线:
(pre)CSSOM ---Blocking----> Evaluate Script -----Blocking-----> DOM
最后,请注意:我们的图片并不会阻止 DOMContentLoaded
事件! 这证明,我们无需等待网页上的每个资源即可构建呈现树甚至绘制网页:不是所有资源均对提供首次描绘起重要作用。事实上,就像我们将要看到的,我们谈论关键呈现路径时,通常谈论的是 HTML 标记、CSS 和 JavaScript。图片不会阻止网页的首次呈现,尽管如此,我们也应努力确保系统尽快绘制图片!
onload 事件标记的点是 网页所需的所有资源均已下载并经过处理 的点,图片资源的加载会影响到 window 的
onload
时间点。
引入外部脚本的 script 标签还支持两个属性:
根据上文对阻塞的分析,我们对于脚本可以采取以下措施:
见链接
优化关键呈现路径常规步骤:
其他提升页面呈现速度的建议: