浏览器是如何渲染页面的
关于浏览器渲染页面, 不得不提的就是 "回流" 和 "重绘".
- <link>
- 标签, 可以用来引入其他文档, 例如 CSS 文件
- <script>
- 标签,
- 可以用来引入脚本文档,
- 例如JavaScript < link > 标签和CSS
浏览器在读取了 < link > 标签后, 会去下载相应的 CSS 文件, 然后会把 CSS 文件的内容解析成 CSS 规则树 (CSS Rule Tree), 接下来整合 DOM 和 CSS 规则树的内容, 确认 DOM 树中每个节点的位置及其样式, 生成渲染树 (Render Tree), 最后浏览器会根据渲染树 "画" 出页面. 在这个过程中, 就发生了回流和重绘.
所谓回流, 简单理解就是确定每个节点的相互关系, 最主要的是位置关系, 显示隐藏.
所谓重绘, 简单理解就是画出每个节点的真实样子.
从这个角度更容易理解为什么回流消耗的资源更多, 而重绘消耗的资源更少, 因为重绘只是单个节点 "自己的事", 回流则会影响到 "别人". 也正因为如此, 我们需要减少回流和重绘.
对于静态页面, 一旦加载完毕, 就不会发生变化, 即不会发生回流和重绘, 需要优化的是第一次加载是时的情况.
针对 CSS 文件, 因为解析完毕后会 "合成" 渲染树, 所以需要尽可能在浏览器解析完标签生成 DOM 树时, 也能生成 CSS 规则树, 这样浏览器根据渲染树渲染出来的页面就是最终的样子, 这是最理想的结果. 这也就是为什么一般我们会把 < link > 标签放在 html 文件的头部. 然而, 浏览器解析 CSS 生成 CSS 规则树的同时会阻塞 DOM 树的生成, 进而导致页面 "白屏". 基于这种考虑, 应该把重要的, 可能会导致元素位置等导致回流的 CSS 的规则所在的文件放在页面头部, 其他仅仅是调整颜色, 背景等 CSS 放到页面底部处理.
<script > 标签和 JS
类似地, 浏览器在读取到 < script > 标签后, 也会去下载相应的 JS 文件, 下载完成后就会解析并执行, 因此会阻塞浏览器的渲染页面. 为了避免影响页面渲染工作, 可以使用 < script > 标签的 defer 或者 async 属性.
defer
defer 会使浏览器异步去下载 JS 文件, 并且在页面渲染完成之后才会执行. 多个带 defer 的 < script > 标签会按照文件顺序依次执行.
async
async 同样会使浏览器异步下载 JS 文件, 并且异步去执行 JS 文件. 多个带 async 的 < script > 标签之间的执行都是异步的, 不能保证先后顺序
来源: http://www.jianshu.com/p/95086e68bef5