看到这个标题你们必定会想到这篇神文《How Browsers Work》,这篇文章把浏览器的不少细节讲得很细,并且也被翻译成了中文。为何我还想写一篇呢?由于两个缘由,php
1)这篇文章太长了,阅读成本太大,不能一口气读完。css
2)花了大力气读了这篇文章后能够了解不少,但彷佛对工做没什么帮助。html
因此,我准备写下这篇文章来解决上述两个问题。但愿你能在上班途中,或是坐马桶时就能读完,并能从中学会一些能用在工做上的东西。web
浏览器工做大流程ajax
废话少说,先来看个图:算法
从上面这个图中,咱们能够看到那么几个事:浏览器
1)浏览器会解析三个东西:app
2)解析完成后,浏览器引擎会经过 DOM Tree 和 CSS Rule Tree 来构造 Rendering Tree。注意:异步
3)最后经过调用操做系统 Native GUI 的 API 绘制。ide
DOM 解析
HTML 的 DOM Tree 解析以下:
<html> <head> <title>Web page parsing</title> </head> <body> <div> <h1>Web page parsing</h1> <p>This is an example Web page.</p> </div> </body> </html>
上面这段 HTML 会解析成这样:
下面是另外一个有 SVG 标签的状况。
CSS 解析
CSS 的解析大概是下面这个样子(下面主要说的是 Gecko 也就是 Firefox 的玩法),假设咱们有下面的 HTML 文档:
<doc> <title>A few quotes</title> <para> Franklin said that <quote>"A penny saved is a penny earned."</quote> </para> <para> FDR said <quote>"We have nothing to fear but <span>fear itself.</span>"</quote> </para> </doc>
因而 DOM Tree 是这个样子:
而后咱们的 CSS 文档是这样的:
/* rule 1 */ doc { display: block; text-indent: 1em; } /* rule 2 */ title { display: block; font-size: 3em; } /* rule 3 */ para { display: block; } /* rule 4 */ [] { font-style: italic; }
因而咱们的 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 结点,不要被其名字所迷惑了。
注:Webkit 不像 Firefox 要用两个树来干这个,Webkit 也有 Style 对象,它直接把这个 Style 对象存在了相应的 DOM 结点上了。
渲染
渲染的流程基本上以下(黄色的四个步骤):
注意:上图流程中有不少链接线,这表示了 Javascript 动态修改了 DOM 属性或是 CSS 属性会致使从新 Layout,有些改变不会,就是那些指到天上的箭头,好比,修改后的 CSS rule 没有被匹配到,等。
这里重要要说两个概念,一个是 Reflow,另外一个是 Repaint。这两个不是一回事。
下面是一个打开 Wikipedia 时的 Layout/reflow 的视频(注:HTML 在初始化的时候也会作一次 reflow,叫 intial reflow),你能够感觉一下:
Reflow 的成本比 Repaint 的成本高得多的多。DOM Tree 里的每一个结点都会有 reflow 方法,一个结点的 reflow 颇有可能致使子结点,甚至父点以及同级结点的 reflow。在一些高性能的电脑上也许还没什么,可是若是 reflow 发生在手机上,那么这个过程是很是痛苦和耗电的。
因此,下面这些动做有很大可能会是成本比较高的。
注:display:none 会触发 reflow,而 visibility:hidden 只会触发 repaint,由于没有发现位置变化。
多说两句关于滚屏的事,一般来讲,若是在滚屏的时候,咱们的页面上的全部的像素都会跟着滚动,那么性能上没什么问题,由于咱们的显卡对于这种把全屏像素往上往下移的算法是很快。可是若是你有一个 fixed 的背景图,或是有些 Element 不跟着滚动,有些 Elment 是动画,那么这个滚动的动做对于浏览器来讲会是至关至关痛苦的一个过程。你能够看到不少这样的网页在滚动的时候性能有多差。由于滚屏也有可能会形成 reflow。
基本上来讲,reflow 有以下的几个缘由:
好了,咱们来看一个示例吧:
var bstyle = document.body.style; // cache bstyle.padding = "20px"; // reflow, repaint bstyle.border = "10px solid red"; // 再一次的 reflow 和 repaint bstyle.color = "blue"; // repaint bstyle.backgroundColor = "#fad"; // repaint bstyle.fontSize = "2em"; // reflow, repaint // new DOM element - reflow, repaint document.body.appendChild (document.createTextNode ('dude!'));
固然,咱们的浏览器是聪明的,它不会像上面那样,你每改一次样式,它就 reflow 或 repaint 一次。通常来讲,浏览器会把这样的操做积攒一批,而后作一次 reflow,这又叫异步 reflow 或增量异步 reflow。可是有些状况浏览器是不会这么作的,好比:resize 窗口,改变了页面默认的字体,等。对于这些操做,浏览器会立刻进行 reflow。
可是有些时候,咱们的脚本会阻止浏览器这么干,好比:若是咱们请求下面的一些 DOM 值:
由于,若是咱们的程序须要这些值,那么浏览器须要返回最新的值,而这样同样会 flush 出去一些样式的改变,从而形成频繁的 reflow/repaint。
减小 reflow/repaint
下面是一些 Best Practices:
1)不要一条一条地修改 DOM 的样式。与其这样,还不如预先定义好 css 的 class,而后修改 DOM 的 className。
// bad var left = 10, top = 10; el.style.left = left + "px"; el.style.top = top + "px"; // Good el.className += " theclassname"; // Good el.style.cssText += "; left: " + left + "px; top: " + top + "px;";
2)把 DOM 离线后修改。如:
3)不要把 DOM 结点的属性值放在一个循环里当成循环里的变量。否则这会致使大量地读写这个结点的属性。
4)尽量的修改层级比较低的 DOM。固然,改变层级比较底的 DOM 有可能会形成大面积的 reflow,可是也可能影响范围很小。
5)为动画的 HTML 元件使用 fixed 或 absoult 的 position,那么修改他们的 CSS 是不会 reflow 的。
6)千万不要使用 table 布局。由于可能很小的一个小改动会形成整个 table 的从新布局。
In this manner, the user agent can begin to lay out the table once the entire first row has been received. Cells in subsequent rows do not affect column widths. Any cell that has content that overflows uses the ‘overflow’ property to determine whether to clip the overflow content.
Fixed layout, CSS 2.1 Specification
This algorithm may be inefficient since it requires the user agent to have access to all the content in the table before determining the final layout and may demand more than one pass.
几个工具和几篇文章
有时候,你会也许会发如今 IE 下,你不知道你修改了什么东西,结果 CPU 一会儿就上去了到 100%,而后过了好几秒钟 repaint/reflow 才完成,这种事情以 IE 的年代时常常发生。因此,咱们须要一些工具帮咱们看看咱们的代码里有没有什么不合适的东西。
最后,别忘了下面这几篇提升浏览器性能的文章:
参考
全文引用自:
浏览器的渲染原理简介: https://news.cnblogs.com/n/178402/