浏览器渲染原理

从输入 URL 到页面加载完成发生了什么事

DNS解析
TCP链接
发送HTTP请求
服务器处理请求并返回HTTP报文
浏览器解析渲染页面

浏览器应该有的功能

网络;资源管理;网页浏览;多页面管理;插件与管理;帐户和同步;安全机制;开发者工具
浏览器的主要功能总结起来就是一句话:
    将用户输入的url转变成可视化的图像

浏览器的内核(渲染引擎)

在浏览器中有一个最重要的模块,它主要的做用是将页面转变为可视化的图像结果。这个模块就是浏览器内核,一般它也被称为渲染引擎。
IE----->Trident
Safari------>WebKit
Chrome;Opera----->Blink
Firefox------>Gecko

渲染引擎

一个渲染引擎主要包括:HTML解析器,CSS解析器,布局layout模块,javascript引擎,绘图模块

渲染过程

1.网页URL到构建DOM树的整个过程
     1) 当用户输入URL的时候,Webkit调用资源加载器加载URL对应的网页
     2) 加载器依赖网络模块创建链接,发送请求并接收答复
     3) Webkit接收到各类网页或者资源的数据,其中某些资源多是同步的或异步获取的
     4) 网页被交给HTML解析器转变一系列的词语(Token)
     5) 解析器根据词语构建节点(node),造成DOM树
     6) 若是节点须要依赖于其余资源,
            例如js css 图片 视频等,调用资源加载器来加载他们,可是这些都是异步的,
            不会阻碍dom树的继续建立;顺序执行  并发加载
            若是资源是css的话
                调用CSS解析器解释将CSS解释成内部表示结构(CSSDOM)
            若是资源是javascript的话
                调用Javascript引擎解释并执行,
     7)阻塞       
            css阻塞                                                                                                       
            css 在head中经过link的形式引入会阻塞页面的渲染   
            为何?            
            避免闪屏现象                                                                                                                          
            js阻塞
            直接引入的js会阻塞页面的渲染
            为何?
            Javascript代码可能会修改DOM树的结构
                    
     8) 预解析
WebKit 和 Firefox 都进行了这项优化。在执行js脚本时,其余线程会解析文档的其他部分,找出并加载须要经过网络加载的其余资源。经过这种方式,资源能够在并行链接上加载,从而提升整体速度。请注意,预解析器不会修改 DOM 树,而是将这项工做交由主解析器处理;
预解析器只会解析外部资源(例如外部脚本、样式表和图片)的引用。

2.从DOM树到可视化图像
    1) CSS文件被CSS解析器解释成内部表示结构(CSSDOM)
    2) CSS解析器工做完成以后,在DOM树上附加解释后的样式信息,这就是RenderObject树
    3) RenderObject在建立的同时,Webkit会根据网页的结构建立RenderLayer,同时构建一个绘图上下文
    4) 根据绘图上下文生成最终的图像(这一过程须要依赖图形库)
     

3.上面介绍的是一个完整的渲染过程,但现代网页不少都是动态的,这意味着在渲染完成以后,因为网页的动画或者用户的交互,
浏览器其实一直在不停地重复执行渲染过程。(重绘重排),以上的数字表示的是基本顺序,这不是严格一致的,
这个过程可能重复也可能交叉。浏览器是一个边解析边渲染的过程

css图层

浏览器在渲染一个页面时,会将页面分为不少个图层,图层有大有小,每一个图层上有一个或多个节点。
在渲染DOM的时候,浏览器所作的工做其实是:
    1. 获取DOM后分割为多个图层
    2. 对每一个图层的节点计算样式结果       (Recalculate style--样式重计算)
    3. 为每一个节点生成图形和位置         (Layout--重排,回流)
    4. 将每一个节点绘制填充到图层位图中      (Paint--重绘)
    5. 图层做为纹理上传至GPU
    6. 符合多个图层到页面上生成最终屏幕图像   (Composite Layers--图层重组)

图层建立的条件

Chrome中知足如下任意状况就会建立图层:
    1. 拥有具备3D变换的CSS属性
    2. 使用加速视频解码的<video>节点
    3. <canvas>节点
    4. CSS3动画的节点
    5. 拥有CSS加速属性的元素(will-change)
    6. 元素有一个z-index较低且包含一个复合层的兄弟元素(换句话说就是该元素在复合层上面渲染)

重绘(Repaint)

重绘是一个元素外观的改变所触发的浏览器行为,例如改变outline、背景色等属性。浏览器会根据元素的新属性从新绘制,
使元素呈现新的外观。重绘不会带来从新布局,因此并不必定伴随重排。

须要注意的是,若是图层中某个元素须要重绘,那么整个图层都须要重绘。
好比一个图层包含不少节点,其中有个gif图,gif图的每一帧,都会重回整个图层的其余节点,而后生成最终的图层位图。
因此这须要经过特殊的方式来强制gif图属于本身一个图层(translateZ(0)或者translate3d(0,0,0)
CSS3的动画也是同样(好在绝大部分状况浏览器本身会为CSS3动画的节点建立图层)

重排(Reflow 回流)

渲染对象在建立完成并添加到渲染树时,并不包含位置和大小信息。计算这些值的过程称为布局或重排

"重绘"不必定须要"重排",好比改变某个网页元素的颜色,就只会触发"重绘",不会触发"重排",由于布局没有改变。
 可是,"重排"必然致使"重绘",好比改变一个网页元素的位置,就会同时触发"重排"和"重绘",由于布局改变了。

触发重绘的属性

* color                             * background                                    * outline-color
        * border-style                      * background-image                              * outline
        * border-radius                     * background-position                           * outline-style
        * visibility                        * background-repeat                             * outline-width
        * text-decoration                   * background-size                               * box-shadow

触发重排(回流)的属性

盒子模型相关属性会触发重布局          定位属性及浮动也会触发重布局:             改变节点内部文字结构也会触发重布局:
        * width                             * top                                           * text-align
        * height                            * bottom                                        * overflow-y
        * padding                           * left                                          * font-weight
        * margin                            * right                                         * overflow
        * display                           * position                                      * font-family
        * border-width                      * float                                         * line-height
        * border                            * clear                                         * vertival-align
        * min-height                                                                        * white-space

常见的触发重排的操做

Reflow 的成本比 Repaint 的成本高得多的多。DOM Tree 里的每一个结点都会有 reflow 方法,
一个结点的 reflow 颇有可能致使子结点,甚至父点以及同级结点的 reflow。在一些高性能的电脑上也许还没什么,
可是若是 reflow 发生在手机上,那么这个过程是很是痛苦和耗电的。

因此,下面这些动做有很大可能会是成本比较高的。
    当你增长、删除、修改 DOM 结点时,会致使 Reflow , Repaint。
    当你移动 DOM 的位置
    当你修改 CSS 样式的时候。
    当你 Resize 窗口的时候(移动端没有这个问题)
    当你修改网页的默认字体时。
    获取某些属性时(width,height...)
    注:display:none 会触发 reflow,而 visibility:hidden 只会触发 repaint,由于没有发生位置变化。

优化

若是咱们须要使得动画或其余节点渲染的性能提升,须要作的就是减小浏览器在运行时所须要作的工做(减小1234中的步骤)
    1. 计算须要被加载到节点上的样式结果(Recalculate style--样式重计算)
    2. 为每一个节点生成图形和位置(Layout--回流和重布局)
    3. 将每一个节点填充到图层中(Paint Setup和Paint--重绘)
    4. 组合图层到页面上(Composite Layers--图层重组)



1.元素位置移动变换时尽可能使用CSS3的transform来代替对top left等的操做
    变换(transform)和透明度(opacity)的改变仅仅影响图层的组合
2.使用opacity来代替visibility
    透明度居然不会触发重绘?
        透明度的改变时,GPU在绘画时只是简单的下降以前已经画好的纹理的alpha值来达到效果,并不须要总体的重绘。
        不过这个前提是这个被修改opacity自己必须是一个图层,若是图层下还有其余节点,GPU也会将他们透明化
3.不要使用table布局



4.将屡次改变样式属性的操做合并成一次操做
    不要一条一条地修改DOM的样式,预先定义好class,而后修改DOM的className
5.将DOM离线后再修改
    因为display属性为none的元素不在渲染树中,对隐藏的元素操做不会引起其余元素的重排。
    若是要对一个元素进行复杂的操做时,能够先隐藏它,操做完成后再显示。这样只在隐藏和显示时触发2次重排。
6.利用文档碎片
7.不要把某些DOM节点的属性值放在一个循环里当成循环的变量
    当你请求向浏览器请求一些 style信息的时候,就会让浏览器flush队列,好比:
        1. offsetTop, offsetLeft, offsetWidth, offsetHeight
        2. scrollTop/Left/Width/Height
        3. clientTop/Left/Width/Height
        4. width,height
    当你请求上面的一些属性的时候,浏览器为了给你最精确的值,须要flush队列,
    由于队列中可能会有影响到这些值的操做。即便你获取元素的布局和样式信息跟最近发生或改变的布局信息无关,
    浏览器都会强行刷新渲染队列。


8.动画实现过程当中,启用GPU硬件加速 
9.为动画元素新建图层,提升动画元素的z-index