浏览器渲染过程及优化
乔文飞 Lv8

熟练使用Chrome开发工具

ChromePerformance

浏览器渲染基础

cpu主要负责操作系统和程序 gpu负责显式 数据处理效率更高 gpu.js

  • Dom是分层的
    firefox的3d插件(已废弃)很好的展现了这个点。
    Q:什么元素会分层?
    A:根元素,position层,transform、半透明、css滤镜、canvas、video、overflow等
  • 对DOM元素节点计算样式结果。(Recalculate Style)
  • 为每个节点生成图形位置。(Layout 回流/重排)
  • 将每个节点绘制填充到图层位图中。(Paint)
  • 把图层作为纹理,上传到GPU
  • 把符合的图层生成到页面上。(Composite Layers 合成层)
    Q:Composite Layers做了啥?
    A:
    图层的绘制列表,准备好,commit给(合成线程)主线程
    合成线程 viewport 划分图块
    生成位图的过程  光栅化 Raster
    所有图块 合成DarwQuad提交给浏览器渲染进程
    viz组件接收到DarwQuad 后,绘制到屏幕上

总结上面过程的主要过程
Layout ==> Paint ==> Composite Layers

渲染引擎结构与工作流程

以HTML、JS、CSS等文件作为输入,以可视化内容作为输出
经过下面步骤:

  1. Parsing HTML to construct DOM tree
    根据html文件生成dom树,框架
  2. Render Tree Construction
    根据css,js文件,在dom树的基础上生成渲染树
  3. Layout of Render Tree
    渲染树布局排版(重排)
  4. Painting Render Tree
    排版之后。绘制(重绘)
  5. Display
    (Composite Layers 合成层,布局树)后,把符合的图层上传到GPU生成到页面上展示。
    • 把文档的结构、元素的样式、几何形状和绘制顺序转换在屏幕上的像素。这个过程称为光栅化
    • 合成是一种将页面的各个部分分层,分别栅格化,并在一个被称为合成器线程的独立线程中合成页面的技术
    • 上传到GPU生成到页面上展示。

浏览器渲染优化

  • 跳过重排重绘 直接触发了GPU执行 这就是硬件加速
    Q:什么会触发硬件加速,让GPU加入进来?
    A:CSS3D、video、webgl、transform、css滤镜、will-change:transform

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    @keyframes ball-running {
    0% {
    top:0;
    left: 0;
    /* transform: translate(0,0); */
    }
    25% {
    top:0;
    left: 200px;
    /* transform: translate(200px,0); */
    }
    50% {
    top:200px;
    left: 200px;
    /* transform: translate(200px,200px); */
    }
    75% {
    top:200px;
    left: 0;
    /* transform: translate(0,200px); */
    }
    }

    上面的动画代码会一直触发重排重绘,性能差
    下面的动画代码将处理交给GPU放在一个layer层中去处理,跳过重排重绘,性能大大提升

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    @keyframes ball-running {
    0% {
    transform: translate(0,0);
    }
    25% {
    transform: translate(200px,0);
    }
    50% {
    transform: translate(200px,200px);
    }
    75% {
    transform: translate(0,200px);
    }
    }

    Q:什么属性会造成重排重绘,导致性能下降?
    A:

    可以参考这个网站:[csstriggers](https://csstriggers.com/)
    盒子模型的盒子变了
    读属性时:offset、scroll、client、width会造成重排(下面为解决方案:requestAnimationFrame)
    
    1
    2
    3
    4
    5
    6
    // 解决方式: 读写分离(读写读写读写===>读读读写写写)
    const width = document.getElementById("xx").width;
    requestAnimationFrame(function(){
    // 写逻辑
    // React Fiber?
    })

大量Dom如何优化

以下内容来自京城一灯小程序Day102题

  • 缓存Dom对象
    操作Dom时,如果有访问Dom的操作。尤其像循环遍历这种时间复杂度较高的操作。
    在循环前将父(主)节点先获取到,在循环中就可以直接饮用,不必要循环查询
    1
    2
    3
    4
    5
    let rootElem = document.querySelector('#app');
    let childList = rootElem.child;
    for(let i=0;i<childList.length;j++){
    //对应操作
    }
  • 文档片段
    利用document.createDocumentFragment()方法创建文档碎片节点,创建的是一个虚拟Dom对象。向这个节点添加Dom节点,修改Dom节点并不会影响到真是的Dom结构。
    我们可以利用这一点先将需要修改的Dom一并修改完,保存至文档碎片中,然后用文档碎片一次性的替换真实的Dom节点。与虚拟Dom类似,也达到了不频繁修改Dom而导致的重排和重绘的过程
    1
    2
    3
    4
    5
    6
    let fragment = document.createDocumentFragment();
    const operationDomHandler = (fragment)=>{
    // 操作
    }
    operationDomHandler(fragment);
    rootElem.replaceChild(fragment, oldDom)
    这样只触发一次回流(重排),效率会打打提升。如果需要对元素进行复杂的操作(删减,添加加点),那么我们应当先将元素从页面中移除,然后再对其进行操作。或者将其复制一个(cloneNode()),在内存中进行操作后再替换原来的节点
    1
    2
    3
    let cloneNode = old.cloneNode(true);
    operationDomHandler(cloneNode);
    rootElem.replaceChild(cloneNode, oldDom);
  • innerHtml代替高频的appendChild
  • 最优的layout方案
    批量读,一次性写。
    先对一个不在render tree上的节点进行操作,在把这个节点添加回render tree。这样只处罚一次Dom操作。使用requestAnimationFrame(),把任何导致重绘的操作放入requestAnimationFrame
    1
    2
    3
    4
    5
    const width = document.getElementById("xx").width;
    requestAnimationFrame(function(){
    // 写逻辑
    // React Fiber?
    })
  • 虚拟Dom
    js模拟Dom树并对Dom树操作的一种技术。Virtual Dom是一个纯js对象(字符串对象),所以对它操作是高效的。
    利用Virtual Dom,将dom抽象为虚拟Dom,在Dom发生改变的时候先将虚拟Dom进行操作,通过Dom diff算法将虚拟Dom和原虚拟Dom的结构对比,最终批量的去修改真是的Dom结构,尽可能的避免了频繁修改Dom而导致的频繁的重排和重绘。

fastdom,处理dom的插件

  • 本文标题:浏览器渲染过程及优化
  • 本文作者:乔文飞
  • 创建时间:2020-07-22 14:32:38
  • 本文链接:http://www.feidom.com/2020/07/22/浏览器渲染过程/
  • 版权声明:本博客所有文章为作者学习笔记,有转载其他前端大佬的文章。转载时请注明出处。