美文网首页javascript
浏览器渲染机制理解

浏览器渲染机制理解

作者: 技术与健康 | 来源:发表于2018-04-22 21:19 被阅读5次

    浏览器渲染机制的复习和整理,主要来自酷壳网和黑色影子在segmengful的文章,对于层和复合层的概念还需要进一步加深学习理解。链接附在文末。

    解析生成DOM Tree/CSS Rule tree

    image.png

    1)浏览器会解析三个东西:

    • 一个是HTML/SVG/XHTML,产生一个DOM Tree。
    • CSS,解析CSS会产生CSS规则树。
    • Javascript,脚本,主要是通过DOM API和CSSOM API来操作DOM Tree和CSS Rule Tree.

    2)解析完成后,浏览器引擎会通过DOM Tree 和 CSS Rule Tree 来构造 Rendering Tree。注意:

    Rendering Tree 渲染树并不等同于DOM树,因为一些像Header或display:none的东西就没必要放在渲染树中了。

    CSS 的 Rule Tree主要是为了完成匹配并把CSS Rule附加上Rendering Tree上的每个Element。也就是DOM结点。也就是所谓的Frame。

    image.png

    然后,计算每个Frame(也就是每个Element)的位置,这又叫layout和reflow过程。
    3)最后通过调用操作系统Native GUI的API绘制。

    渲染的流程基本上如下(黄色的四个步骤):

    1. 计算CSS样式
    2. 构建Render Tree
    3. Layout – 定位坐标和大小,是否换行,各种position, overflow, z-index属性 ……
    4. 正式开画
    image

    注意:上图流程中有很多连接线,这表示了Javascript动态修改了DOM属性或是CSS属会导致重新Layout,有些改变不会,就是那些指到天上的箭头,比如,修改后的CSS rule没有被匹配到,等。

    这里重要要说两个概念,一个是Reflow,另一个是Repaint。这两个不是一回事。

    • Repaint——屏幕的一部分要重画,比如某个CSS的背景色变了。但是元素的几何尺寸没有变。

    • Reflow——意味着元件的几何尺寸变了,我们需要重新验证并计算Render Tree。是Render Tree的一部分或全部发生了变化。这就是Reflow,或是Layout。(HTML使用的是flow based layout,也就是流式布局,所以,如果某元件的几何尺寸发生了变化,需要重新布局,也就叫reflow)reflow 会从<html>这个root frame开始递归往下,依次计算所有的结点几何尺寸和位置,在reflow过程中,可能会增加一些frame,比如一个文本字符串必需被包装起来。

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

    减少reflow/repaint
    下面是一些Best Practices:

    下面是一些针对reflow和repaint的最佳实践:

    • 不要一条一条地修改dom的样式,尽量使用className一次修改。

    • 将dom离线后修改

      • 使用documentFragment对象在内存里操作dom。

      • 先把dom节点display:none;(会触发一次reflow)。然后做大量的修改后,再把它显示出来。

      • clone一个dom节点在内存里,修改之后;与在线的节点相替换。

    • 不要使用table布局,一个小改动会造成整个table的重新布局。

    • transform和opacity只会引起合成,不会引起布局和重绘。

    从上述的最佳实践中你可能发现,动画优化一般都是尽可能地减少reflow、repaint的发生。关于哪些属性会引起reflow、repaint及composite,你可以在这个网站找到https://csstriggers.com/

    Composite

    在reflow和repaint之后,浏览器会将多个复合层传入GPU;进行合成工作,那么合成是如何工作的呢?

    GPU实际上可以看作一个独立的计算机,它有自己的处理器和存储器及数据处理模型。当浏览器向GPU发送消息的时候,就像向一个外部设备发送消息。

    浏览器向GPU发送数据也需要先创建一个载体;只不过GPU距离CPU很近,不会像远程服务器那样可能几千里那么远。但是对于远程服务器,2秒的延迟是可以接受的;但是对于GPU,几毫秒的延迟都会造成动画的卡顿。

    浏览器向GPU发送的数据载体是什么样?这里给出一个简单的制作载体,并把它们发送到GPU的过程。

    画每个复合层的图像
    
    准备图层的数据
    
    准备动画的着色器(如果需要)
    
    向GPU发送数据
    

    为了仅发生composite,我们做动画的css property必须满足以下三个条件:

    不影响文档流。
    
    不依赖文档流。
    
    不会造成重绘。
    

    满足以上以上条件的css property只有transform和opacity。你可能以为position也满足以上条件,但事实不是这样,举个例子left属性可以使用百分比的值,依赖于它的offset parent。还有em、vh等其他单位也依赖于他们的环境

    浏览器在动画执行之前就知道动画如何开始和结束,因为浏览器没有看到需要reflow和repaint的操作;浏览器就会画两张图像作为复合层,并将它们传入GPU。

    这样做有两个优势:

    • 动画将会非常流畅

    • 动画不在绑定到CPU,即使js执行大量的工作;动画依然流畅

    优化技巧总结

    减少浏览器的重排和重绘的发生。
    
    不要使用table布局。
    
    css动画中尽量只使用transform和opacity,这不会发生重排和重绘。
    
    尽可能地只使用css做动画。
    

    css动画有一个重要的特性,它是完全工作在GPU上。因为你声明了一个动画如何开始和如何结束,浏览器会在动画开始前准备好所有需要的指令;并把它们发送给GPU。而如果使用js动画,浏览器必须计算每一帧的状态;为了保证平滑的动画,我们必须在浏览器主线程计算新状态;把它们发送给GPU至少60次每秒。除了计算和发送数据比css动画要慢,主线程的负载也会影响动画; 当主线程的计算任务过多时,会造成动画的延迟、卡顿。

    所以尽可能地使用基于css的动画,不仅仅更快;也不会被大量的js计算所阻塞。

    避免浏览器的隐式合成。
    
    改变复合层的尺寸
    

    参考:
    https://segmentfault.com/a/1190000008015671
    https://coolshell.cn/articles/9666.html/comment-page-2#comments

    相关文章

      网友评论

        本文标题:浏览器渲染机制理解

        本文链接:https://www.haomeiwen.com/subject/agzclftx.html