JavaScript中的Repaint和Reflow用法详解


Posted in Javascript onJuly 27, 2015

你是不是经常听师兄或一些前端前辈说不能用CSS通配符 *,CSS选择器层叠不能超过三层,CSS尽量使用类选择器,书写HTML少使用table,结构要尽量简单-DOM树要小....等这些忠告,以前我就大概知道使用通配符或者CSS选择器层次过多可能会降低性能,至于为什么不使用table标签我一直是迷迷糊糊,也就跟着那样做了,但我认识了Repain和 Reflow之后,原来这些还真不能用太多。 ok,希望这篇文章对你有帮助!

1.什么是Repaint/Reflow?

好,先上一张图:浏览器解析大概的工作流程

JavaScript中的Repaint和Reflow用法详解

这张图应该可以很好理解,归纳为四个步骤:

1、解析HTML以构建DOM树:渲染引擎开始解析HTML文档,转换树中的html标签或js生成的标签到DOM节点,它被称为 -- 内容树。
2、构建渲染树:解析CSS(包括外部CSS文件和样式元素以及js生成的样式),根据CSS选择器计算出节点的样式,创建另一个树 —- 渲染树。
3、布局渲染树: 从根节点递归调用,计算每一个元素的大小、位置等,给每个节点所应该出现在屏幕上的精确坐标。
4、绘制渲染树: 遍历渲染树,每个节点将使用UI后端层来绘制。

好,我们可以看到Repain 和 Reflow 分别出现在了第三和第四步。因此我们给出下面的定义:

    对于DOM结构中的各个元素都有自己的盒子(模型),这些都需要浏览器根据各种样式(浏览器的、开发人员定义的等)来计算并根据计算结果将元素放到它该出现的位置,这个过程称之为reflow;当各种盒子的位置、大小以及其他属性,例如颜色、字体大小等都确定下来后,浏览器于是便把这些元素都按照各自的特性绘制了一遍,于是页面的内容出现了,这个过程称之为repaint。
    可见这两个东东对浏览器渲染页面是很重要的啊,都是会影响性能的,因此我们需要了解一些常见的会引起repaint和reflow的一些操作,并且应该尽量减少以提高渲染速度。

2.引起Repain和Reflow的一些操作

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

  •     当你增加、删除、修改 DOM 结点时,会导致 Reflow 或 Repaint。
  •     当你移动 DOM 的位置,或是搞个动画的时候。
  •     当你修改 CSS 样式的时候。
  •     当你 Resize 窗口的时候(移动端没有这个问题),或是滚动的时候。
  •     当你修改网页的默认字体时。

注:display:none 会触发 reflow,而 visibility:hidden 只会触发 repaint,因为没有发现位置变化。
3.如何优化?

Reflow是不可避免的,只能将Reflow对性能的影响减到最小,给出下面几条建议:

    不要一条一条地修改 DOM 的样式。与其这样,还不如预先定义好 css 的 class,然后修改 DOM 的 className:

   

// 不好的写法
  var left = 10,
  top = 10;
  el.style.left = left + "px";
  el.style.top = top + "px";
  // 推荐写法
  el.className += " theclassname";

    把 DOM 离线后修改。如:
    a> 使用 documentFragment 对象在内存里操作 DOM。
    b> 先把 DOM 给 display:none (有一次 repaint),然后你想怎么改就怎么改。比如修改 100 次,然后再把他显示出来。
    c> clone 一个 DOM 节点到内存里,然后想怎么改就怎么改,改完后,和在线的那个的交换一下。

    不要把 DOM 节点的属性值放在一个循环里当成循环里的变量。不然这会导致大量地读写这个结点的属性。

    尽可能的修改层级比较低的 DOM节点。当然,改变层级比较底的 DOM节点有可能会造成大面积的 reflow,但是也可能影响范围很小。

    为动画的 HTML 元件使用 fixed 或 absoult 的 position,那么修改他们的 CSS 是会大大减小 reflow 。

    千万不要使用 table 布局。因为可能很小的一个小改动会造成整个 table 的重新布局。

认识了这些是不是对浏览器的原理有更大兴趣了?OK,后面会更新关于浏览器原理的文章,或者你们可以先去搜搜别人的,因为我觉得理解浏览器的原理确实是很重要,可以帮助我们写出性能更好的website。

Javascript 相关文章推荐
JavaScript 浏览器验证代码(来自discuz)
Jul 17 Javascript
javascript设计模式 封装和信息隐藏(上)
Jul 24 Javascript
页面载入结束自动调用js函数示例
Sep 23 Javascript
js history对象简单实现返回和前进
Oct 30 Javascript
浅析JavaScript中的常用算法与函数
Nov 21 Javascript
javascript window.open打开新窗口后无法再次打开该窗口问题的解决方法
Apr 12 Javascript
js实现简单div拖拽功能实例
May 12 Javascript
详解vue组件通信的三种方式
Jun 30 Javascript
JS FormData上传文件的设置方法
Jul 05 Javascript
angular6开发steps步骤条组件
Jul 04 Javascript
electron-vue开发环境内存泄漏问题汇总
Oct 10 Javascript
vue同个按钮控制展开和折叠同个事件操作
Jul 29 Javascript
javascript实现类似java中getClass()得到对象类名的方法
Jul 27 #Javascript
AngularJS的一些基本样式初窥
Jul 27 #Javascript
javascript实现网页子页面遍历回调的方法(涉及 window.frames、递归函数、函数上下文)
Jul 27 #Javascript
JavaScript数组对象实现增加一个返回随机元素的方法
Jul 27 #Javascript
使用HTML+CSS+JS制作简单的网页菜单界面
Jul 27 #Javascript
Javascript验证Visa和MasterCard信用卡号的方法
Jul 27 #Javascript
JavaScript实现自动对页面上敏感词进行屏蔽的方法
Jul 27 #Javascript
You might like
php下检测字符串是否是utf8编码的代码
2008/06/28 PHP
windows服务器中检测PHP SSL是否开启以及开启SSL的方法
2014/04/25 PHP
刷新PHP缓冲区为你的站点加速
2015/10/10 PHP
PHP实现适用于文件内容操作的分页类
2016/06/15 PHP
PHP中利用sleep函数实现定时执行功能实现代码
2016/08/25 PHP
PHP版微信第三方实现一键登录及获取用户信息的方法
2016/10/14 PHP
解决windows上php xdebug 无法调试的问题
2020/02/19 PHP
jQuery实现返回顶部效果的方法
2015/05/29 Javascript
JavaScript中使用指数方法Math.exp()的简介
2015/06/15 Javascript
全面解析Bootstrap图片轮播效果
2015/12/03 Javascript
js获取当前日期时间及其它日期操作汇总
2016/03/08 Javascript
js 判断一组日期是否是连续的简单实例
2016/07/11 Javascript
jQuery插件ajaxFileUpload异步上传文件
2016/10/19 Javascript
如何学JavaScript?前辈的经验之谈
2016/12/28 Javascript
本地搭建微信小程序服务器的实现方法
2017/10/27 Javascript
Vue-cli配置打包文件本地使用的教程图解
2018/08/02 Javascript
Web安全之XSS攻击与防御小结
2018/12/13 Javascript
微信小程序自定义多列选择器使用详解
2019/06/21 Javascript
JavaScript canvas实现雨滴特效
2021/01/10 Javascript
[03:46]显微镜下的DOTA2第七期——满血与残血
2014/06/20 DOTA
[02:22:36]《加油!DOTA》总决赛
2014/09/19 DOTA
[01:57]DOTA2上海特锦赛小组赛解说单车采访花絮
2016/02/27 DOTA
[02:07]2017国际邀请赛中国区预选赛直邀战队前瞻
2017/06/23 DOTA
Python查询Mysql时返回字典结构的代码
2012/06/18 Python
matplotlib给子图添加图例的方法
2018/08/03 Python
Django Rest framework之权限的实现示例
2018/12/17 Python
借助Paramiko通过Python实现linux远程登陆及sftp的操作
2020/03/16 Python
keras 获取某层输出 获取复用层的多次输出实例
2020/05/23 Python
pyx文件 生成pyd 文件用于 cython调用的实现
2021/03/04 Python
全面总结使用CSS实现水平垂直居中效果的方法
2016/03/10 HTML / CSS
使用HTML5在网页中嵌入音频和视频播放的基本方法
2016/02/22 HTML / CSS
说出数据连接池的工作机制是什么?
2013/04/19 面试题
用Java语言将一个键盘输入的数字转化成中文输出
2013/01/25 面试题
装饰工程师岗位职责
2014/06/08 职场文书
2014年党风廉政建设工作总结
2014/11/19 职场文书
表扬信格式模板
2015/05/05 职场文书