资讯专栏INFORMATION COLUMN

前端性能之回流与重绘(reflow && repaint)

ytwman / 1471人阅读

摘要:写在金三银四之际。一个节点触发了,浏览器会检查中其他所有节点的显示方式一个节点触发了会导致它的祖先节点,后代节点以及在它之后的节点全部。对性能的影响大于。解决方式控制我们无力去改变,对性能损害的程度,我们能做的只有减少它们发生的次数。

写在金三银四之际。
因为种种原因想要谋求新的发展,不得已翻起了尘封已久的高程书;写起了各种经典CSS布局;回顾起记忆略显模糊的几个项目。感慨着太多太多的知识点自己都不够深入甚至缺乏认识,却又不能急功近利,囫囵吞枣。
牢骚发完了,苦水吐完了,进入正题。
万恶之源——无知

回流(reflow),重绘(repaint)都是浏览器更新页面视图的方式,区别在于:

对于元素视觉上的改变(如改变outline,background-color,visibility等)会触发repaint;

对于元素布局上的改变(增删节点,触发resize事件,修改style属性等)会触发reflow;

repaint和reflow是DOM操作影响性能的主要原因。一个节点触发了repaint,浏览器会检查DOM Tree中其他所有节点的显示方式;一个节点触发了reflow会导致它的祖先节点,后代节点以及在它之后的节点全部reflow。reflow对性能的影响大于repaint。

一个前端开发人员对这些概念一无所知是一件很恐怖的事情,想想他在写代码的时候不知道哪些操作会对性能造成影响,可能会出现这种情况:

var toChange = document.getElementById("target");
toChange.style.background = "#333";
toChange.style.color = "#fff";
toChange.style.border = "1px solid #00f";

这无疑是可以优化的,下面我们来看看如何减少reflow,repaint的次数。

解决方式——控制

我们无力去改变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);

再比如像上面style那个例子,如果已知变化后样式,将这些样式写成一个class,再去改变元素的class或者直接修改cssText属性,这两种方式都将多次reflow缩减为一次。

复制

对复制品进行操作也是一种解决方案,比如需要对已有节点进行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,在第一次调用时存起来也是复制的一种。

舍弃

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

其他

减少table的使用,table造成的reflow是其他块级元素的三倍;

尽量避免改变DOM Tree中高层节点的class,减小reflow的影响;

利用各种选择器规则减少待操作节点的数量;

最后,我认为理解reflow和repaint的原理及触发情况是十分重要的,在写每一行代码时都应该明确它对性能的影响。

参考文章:
REFLOWS & REPAINTS: CSS PERFORMANCE MAKING YOUR JAVASCRIPT SLOW?

Effecitve JavaScript

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/93407.html

相关文章

  • 性能:深入理解浏览器渲染原理 reflow &amp; repaint

    摘要:之后,如果渲染树发生了变动,那么可能会触发回流或重绘中的一个或二者。在书写时要避免不必要的层级,书写时避免嵌套过深规则过于复杂,尤其是后代选择器,匹配选择器也会耗费更多的。 刚入行前端的时候是不是经常看到有文章说尽量不要用CSS通配符*,CSS选择器层叠最好不要超过三层,HTML少使用table,结构也要尽量简单一些...这一切说的不无道理,过多的使用确实会造成浏览器渲染的性能降低,当...

    WelliJhon 评论0 收藏0
  • 前端性能优化——回流重绘

    摘要:前言最近在研究,接着就研究回顾起回流与重绘了。回流与重绘,好像大家都很熟悉的样子,但是要具体来说说,又说不出什么来。注意回流必将引起重绘,而重绘不一定会引起回流。 前言 最近在研究virtual dom,接着就研究回顾起回流(reflow)与重绘(repaint)了。 回流与重绘,好像大家都很熟悉的样子,但是要具体来说说,又说不出什么来。下面我是我稍做的整理: 浏览器渲染流程 在理解这...

    endiat 评论0 收藏0
  • 前端性能优化——回流重绘

    摘要:前言最近在研究,接着就研究回顾起回流与重绘了。回流与重绘,好像大家都很熟悉的样子,但是要具体来说说,又说不出什么来。注意回流必将引起重绘,而重绘不一定会引起回流。 前言 最近在研究virtual dom,接着就研究回顾起回流(reflow)与重绘(repaint)了。 回流与重绘,好像大家都很熟悉的样子,但是要具体来说说,又说不出什么来。下面我是我稍做的整理: 浏览器渲染流程 在理解这...

    Michael_Lin 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<