当咱们打开一个浏览器,输入一个url,按下回车,不用多久,一个漂亮的页面就呈如今咱们眼前了。其实,在咱们等待页面打开的这段时间里,浏览器但是作了很多的事情,究竟是什么事情呢,就咱们一块儿来看看吧css
首先,咱们须要先了解一下什么是页面渲染以及页面渲染的整个过程~html
一、页面渲染浏览器
简单地说,页面渲染就是浏览器将 HTML 代码根据 CSS 定义的规则显示在浏览器窗口中的这个过程服务器
二、渲染过程布局
1. 用户输入网址(假设是个 HTML 页面,而且是第一次访问),浏览器向服务器发出请求,服务器返回 HTML 文件;性能
2. 浏览器开始载入 HTML 代码,发现 <head> 标签内有一个 <link> 标签引用外部 CSS 文件;学习
3. 浏览器又发出 CSS 文件的请求,服务器返回这个 CSS 文件;字体
4. 浏览器继续载入 HTML 中 <body> 部分的代码,而且 CSS 文件已经拿到手了,能够开始渲染页面了;优化
5. 浏览器在代码中发现一个 <img> 标签引用了一张图片,向服务器发出请求。此时浏览器不会等到图片下载完,而是继续渲染后面的代码;动画
6. 服务器返回图片文件,因为图片占用了必定面积,影响了后面段落的排布,所以浏览器须要回过头来从新渲染这部分代码;
7. 浏览器发现了一个包含一行 JavaScript 代码的 <script> 标签,赶快运行它;
8. JavaScript 脚本执行了这条语句,它命令浏览器隐藏掉代码中的某个 <div>(style.display=”none”)。杯具啊,忽然就少了这么一个元素,浏览器不得不从新渲染这部分代码;
9. 终于等到了 </html> 的到来,浏览器泪流满面……
10. 等等,还没完,用户点了一下界面中的“换肤”按钮,JavaScript 让浏览器换了一下 <link> 标签的 CSS 路径;
11. 浏览器召集了在座的各位 <div><span><ul><li> 们,“大伙儿收拾收拾行李,咱得从新来过……”,浏览器向服务器请求了新的CSS文件,从新渲染页面。
如今你们已经知道什么是页面渲染了吧,接下来再介绍两个概念,reflow和repaint~
三、reflow(回流)
首先说一下页面为何会慢?那是由于浏览器要花时间、花精力去渲染,尤为是当它发现某个部分发生了点变化影响了布局,须要倒回去从新渲染,内行称这个回退的过程叫 reflow
下面这张图很清晰的说明了这个过程
reflow 几乎是没法避免的。如今界面上流行的一些效果,好比树状目录的折叠、展开(实质上是元素的显 示与隐藏)等,都将引发浏览器的 reflow。鼠标滑过、点击……只要这些行为引发了页面上某些元素的占位面积、定位方式、边距等属性的变化,都会引发它内部、周围甚至整个页面的从新渲 染。一般咱们都没法预估浏览器到底会 reflow 哪一部分的代码,它们都彼此相互影响着。
固然,reflow 问题是能够优化的,咱们能够尽可能减小没必要要的 reflow。好比开头的例子中的 <img> 图片载入问题,这其实就是一个能够避免的 reflow —— 给图片设置宽度和高度就能够了。这样浏览器就知道了图片的占位面积,在载入图片前就预留好了位置。
四、repaint(重绘)
另外,有个和 reflow 看上去差很少的术语:repaint,中文叫重绘。若是只是改变某个元素的背景色、文 字颜色、边框颜色等等不影响它周围或内部布局的属性,将只会引发浏览器 repaint。repaint 的速度明显快于 reflow(在IE下须要换一下说法,reflow 要比 repaint 更缓慢)。
学习了上面的知识后,相信你们对浏览器渲染已经有了一个比较深入的了解了吧,接下来让咱们进行更深刻的学习
五、浏览器工做大体流程
从上面这个图中,咱们能够看到那么几个事:
1)浏览器会解析三个东西:
2)解析完成后,浏览器引擎会经过 DOM Tree 和 CSS Rule Tree 来构造 Rendering Tree。注意:
3)最后经过调用操做系统 Native GUI 的 API 绘制。
六、DOM解析
HTML 的 DOM Tree 解析以下:
上面这段 HTML 会解析成这样:
下面是另外一个有 SVG 标签的状况:
七、CSS 解析
CSS 的解析大概是下面这个样子(下面主要说的是 Gecko 也就是 Firefox 的玩法),假设咱们有下面的 HTML 文档:
因而 DOM Tree 是这个样子:
而后咱们的 CSS 文档是这样的:
因而咱们的 CSS Rule Tree 会是这个样子:
注意,图中的第 4 条规则出现了两次,一次是独立的,一次是在规则 3 的子结点。因此,咱们能够知道,创建 CSS Rule Tree 是须要比照着 DOM Tree 来的。CSS 匹配 DOM Tree 主要是从右到左解析 CSS 的 Selector,好多人觉得这个事会比较快,其实并不必定。关键还看咱们的 CSS 的 Selector 怎么写了。
注意:CSS 匹配 HTML 元素是一个至关复杂和有性能问题的事情。因此,你就会在N多地方看到不少人都告诉你,DOM 树要小,CSS 尽可能用 id 和 class,千万不要过渡层叠下去,……
经过这两个树,咱们能够获得一个叫 Style Context Tree,也就是下面这样(把 CSS Rule 结点 Attach 到 DOM Tree 上):
因此,Firefox 基本上来讲是经过 CSS 解析生成 CSS Rule Tree,而后,经过比对 DOM 生成 Style Context Tree,而后 Firefox 经过把 Style Context Tree 和其 Render Tree(Frame Tree)关联上,就完成了。注意:Render Tree 会把一些不可见的结点去除掉。而 Firefox 中所谓的 Frame 就是一个 DOM 结点,不要被其名字所迷惑了。
八、重说渲染
渲染的流程基本上以下(黄色的四个步骤):
(1)计算 CSS 样式
(2)构建 Render Tree
(3)Layout – 定位坐标和大小,是否换行,各类 position, overflow, z-index 属性 ……
(4)正式开画
注意:上图流程中有不少链接线,这表示了 Javascript 动态修改了 DOM 属性或是 CSS 属性会致使从新 Layout,有些改变不会,就是那些指到天上的箭头,好比,修改后的 CSS rule 没有被匹配到,等。
这里从新说下两个概念,一个是 Reflow,另外一个是 Repaint。这两个不是一回事。
因此,下面这些动做有很大可能会是成本比较高的。
注:display:none 会触发 reflow,而 visibility:hidden 只会触发 repaint,由于没有发现位置变化。
九、一些优化建议
(1)不要一条一条地修改 DOM 的样式。与其这样,还不如预先定义好 css 的 class,而后修改 DOM 的 className
(2)把 DOM 离线后修改。如:
(3)不要把 DOM 结点的属性值放在一个循环里当成循环里的变量。否则这会致使大量地读写这个结点的属性。
(4)尽量的修改层级比较低的 DOM。固然,改变层级比较底的 DOM 有可能会形成大面积的 reflow,可是也可能影响范围很小。
(5)为动画的 HTML 元件使用 fixed 或 absoult 的 position,那么修改他们的 CSS 是不会 reflow 的。
(6)千万不要使用 table 布局。由于可能很小的一个小改动会形成整个 table 的从新布局。