• 前端性能:回流与重绘的学习


    浏览器

    1. 浏览器使用流式布局模型
    2. 浏览器将html解析成DOM,把css解析成CSSOM,DOM和CSSOM合并产生渲染树RenderTree
    3. 根据RenderTree,浏览器计算元素在页面上的大小和位置,然后把节点绘制在页面上
    4. 流式布局的特点:一般对RenderTree遍历一次就可以完成页面渲染。但是table及其内部元素可能要进行多次运算才能完成渲染。

    回流

    当渲染树中部分或全部元素的尺寸、结构、边距等某些属性发生改变时,浏览器重新渲染部分或者全部文档的过程
    导致回流的操作:

    • 页面首次渲染、浏览器窗口大小发生改变
    • 元素几何属性发生变化,尺寸或者位置发生改变
    • 元素内容发生改变,比如文字数量或者图片大小等
    • 元素字体大小变化(应该是不算c3?)
    • DOM树结构变化,添加或者删除可见的DOM元素
    • CSS伪类激活,例如hover(?真的吗)
    • 获取某些属性,offsetTop、offsetLeft、 offsetWidth、offsetHeight、scrollTop、scrollLeft、scrollWidth、scrollHeight、 clientTop、clientLeft、clientWidth、clientHeight、getComputedStyle() (currentStyle in IE)。所以,在多次使用这些值时应进行缓存。

    重绘

    当元素的一部分属性发生变化,如color、background-color、visibility等,不会影响元素在文档流中的位置,不需要重新渲染,浏览器只是将新样式赋给元素并重新绘制它

    var s = document.body.style;
    s.padding = "2px"; // 回流+重绘
    s.border = "1px solid red"; // 再一次 回流+重绘
    s.color = "blue"; // 再一次重绘
    s.backgroundColor = "#ccc"; // 再一次 重绘
    s.fontSize = "14px"; // 再一次 回流+重绘
    // 添加node,再一次 回流+重绘
    document.body.appendChild(document.createTextNode('abc!'));
    

    如何避免

    浏览器应对机制:队列中的操作到了一定的数量或者到了一定的时间间隔,就会flush队列,进行批量处理。

    • 控制
      尽量减少repaint和reflow的次数,并且repaint对性能的影响小于reflow。
    • 脱离
      动画时时刻刻都在操作着DOM,为了避免动画使得其他节点也在时时刻刻reflow,可以将动画所在的元素设为position: fixed或者position: absolute,使其脱离文档流,这个元素reflow时不会影响其他节点的布局,虽然还是会产生repaint,但相对来说得到了优化。
    • 合并
      能一次完成的操作就不要分两次。添加多个节点时使用DocumentFragment,处理完之后再一起更新:
    var docFragm = document.createDocumentFragment();
    var elem, contents;
    for(var i = 0; i < textlist.length; i++) {
        elem = document.createElement('p');
        contents = document.createTextNode(textlist[i]);
        elem.appendChild(contents);
        docFragm.appendChild(elem);
    }
    document.body.appendChild(docFragm);
    
    • 复制
      对复制品进行操作,对已有节点进行DOM操作使用cloneNode():
    var original = document.getElementById('container');
    var cloned = original.cloneNode(true);
    cloned.setAttribute('width', '50%');
    var elem, contents;
    for(var i = 0; i < textlist.length; i++) {
        elem = document.createElement('p');
        contents = document.createTextNode(textlist[i]);
        elem.appendChild(contents);
        cloned.appendChild(elem);
    }
    //先复制,再进行替代
    original.parentNode.replaceChild(cloned, original);
    

    使用cloneNode()要注意的是,唯一的参数代表是否进行深复制。另外cloneNode()无法复制事件监听函数,以及表单控件的value。
    又比如获取offsetWidth,getComputedStyle()这些取值操作每次都会触发reflow,在第一次调用时存起来也是复制的一种。

    • 舍弃
      在做好了其他优化措施的前提下想要进一步提升性能有时需要舍弃,比如减小动画帧数,即增大动画函数执行的间隔,这样动画流畅程度会降低,但整个应用的性能得到了提升。
    • 分类归纳

    CSS:

    1. 避免使用table布局。
    2. 尽可能在DOM树的最末端改变class。
    3. 避免设置多层内联样式。
    4. 将动画效果应用到position属性为absolute或fixed的元素上。
    5. 避免使用CSS表达式(例如:calc())。

    javascript:

    1. 避免频繁操作样式,最好一次性重写style属性,或者将样式列表定义为class并一次性更改class属性。
    2. 避免频繁操作DOM,创建一个documentFragment,在它上面应用所有DOM操作,最后再把它添加到文档中。
    3. 也可以先为元素设置display: none,操作结束后再把它显示出来。因为在display属性为none的元素上进行的DOM操作不会引发回流和重绘。
    4. 避免频繁读取会引发回流/重绘的属性,如果确实需要多次使用,就用一个变量缓存起来。
    5. 对具有复杂动画的元素使用position:absolute,使它脱离文档流,否则会引起父元素及后续元素频繁回流。

    回流一定产生重绘,重绘不一定产生回流

  • 相关阅读:
    Linux 系统高级编程 ¶
    手表维修_机械表维修_手表维修网
    epel
    集合包含关系的快速算法 simcity 博客园
    微软的无线鼠标的电池用的快啊,今天又换新的了
    VIM字符集编码设置_icewater_新浪博客
    【索尼LT29i】索尼(SONY)LT29i 3G手机(黑色)WCDMA/GSM 【行情 报价 价格 评测】
    Python模块学习 fileinput 成长的点滴,记录与分享 博客频道 CSDN.NET
    fedora8 使用小记之:终端字体设置
    Wen Quan Yi Open Source Chinese: About
  • 原文地址:https://www.cnblogs.com/vera-7c/p/13045692.html
Copyright © 2020-2023  润新知