【DOM】重绘与重排详解及在性能优化中的应用

这篇具有很好参考价值的文章主要介绍了【DOM】重绘与重排详解及在性能优化中的应用。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

DOM树

表示页面结构

渲染树

表示DOM节点如何展示

DOM树中需要展示的节点在渲染树中至少存在一个对应的节点(隐藏的DOM元素在渲染树中没有对应的节点)。渲染树中的节点被称为“帧(frames)”或“盒(boxes)”。符合CSS模型的定义。理解页面元素为一个具有内边距、外边距、边框、位置的盒子。一旦DOM和渲染树构建完成,浏览器就开始显示(绘制 paint)页面元素。

当DOM元素变化影响了元素的集合属性(宽和高)——比如改变边框宽度或者给段落添加文字,导致行数增加——浏览器需要重新计算元素的几何属性, 同样其他元素的几何属性和位置也会因此受到影响。 浏览器会使渲染树中受到影响的部分失效, 并重新构造渲染树。 这个过程称为 “ 重排(reflow)”。完成重排后, 阅览器会重新绘制受影响的部分到屏幕中,该过程称为 “ 重绘(repaint)"。

并不是所有的DOM变化都会影响几何属性。 例如, 改变一个元素的背景色并不会影响色的宽和高。 在这种情况下, 只会发生一次重绘(不需要重排), 因为元素的布局并没有改变。

重绘和重排操作都是代价昂贵的操作,它们会导致 Web 应用程序的 UI 反应迟钝。所以, 应当尽可能减少这类过程的发生。

重排何时发生

正如前文所提到的, 当页面布局和几何属性改变时就需要“重排”。下述情况中会发生重排。

  • 添加或删除可见的DOM元素。
  • 元素位置改变。
  • 元素尺寸改变(包括:夕|、边距、 内边距、 边框厚度、 宽度、 高度等属性改变)。内容改变, 例如: 文本改变或图片被另一个不同尺寸的图片替代。
  • 页面谊染器初始化。
  • 浏览器窗口尺寸改变。

根据改变的范围和程度, 渲染树中或大或小的对应的部分也需要重新计算。 有些改变会触发整个页面的重排: 例如, 当滚动条出现时。

渲染树变化的排队与刷新

由干每次重排都会产生计算消耗, 大多数浏览器通过队列化修改并批量执行来优化重排过程。 然而, 你可能会(经常不知不觉)强制刷新队列并要求计划任务立刻执行。 获取布局信息的操作会导致歹lj队刷新, 比如以下方法:

  • offsetTop, offsetleft, offsetWidth, offsetHeight
  • scrollTop, scrollleft, scrollWidth, scrollHeight
  • clientTop, clientleft, clientWidth, clientHeight
  • getComputedStyle() (currentStyle in IE)

以上属性和方在是需要返回最新的布局信息, 因此浏览器不得不执行渲染列队中的 “待处理变化” 井触发重排以返回正确的值。

在修改样式的过程中, 最好避免使用上面列出的属性。它们都会刷新渲染队列, 即使你是在获取最近未发生改变的或者与最新改变无关的布局信息。

最小化重绘和重排

重绘和重排可能代价非常昂贵,因此一个好的提高程序响应速度的策略就是减少此类操作的发生。为了减少发生次数,应该合并多次对DOM和样式的修改,然后一次处理掉。

改变样式

考虑这个例子:

var el= document.getElementByid( 'mydiv'); 
el.style.borderleft = 'lpx'  
el. style.borderRight = '2px '
el. style.padding = '5px'

示例中有三个样式属性被改变,每一 个都会影响元素的几何结构。 最糟糕的情况下,会导致浏览器触发三次重排。 大部分现代浏览器为此做了优化, 只会触发一次重排, 但是在旧版浏览器中或者有一个分离的异步处理过程时(比如使用计时器), 仍然效率低下。 如果在 上面代码执行时, 有其他代码请求布局信息, 这会导致触发三次重排。 而且, 这段代码四 次访问DOM, 可以被优化。

够达到同样效果且效率更高的方式是: 合并所有的改变然后一次处理, 这样只会修改DOM一次。 使用cssText属性可以实现:

el.style.cssText += ' ;border-left: 1px' ;

另一个一次性修改样式的办法是修改 css的class名称, 而不是修改内联样式。 这种方法适合那些不依赖于运行逻辑和计算的情况。 改变 css 的class名称的方也更清晰, 更易于维护。它有助于保持你的脚本与免除显示性代码, 尽管它可能带来轻微的性能影响, 因为 改变类时需要检查级联样式。

var el= document.getElementByld('mydiv'); 
el.className ='active'

批量修改DOM

当需要对DOM元素进行一系列操作时, 可以通过以下步骤来减少重绘和重排的次数:

  1. 使元素脱离文档流。
  2. 对其应用多重改变。
  3. 把元素带回文档中。

该过程里会触发两次重排一一一第一步和第三步。 如果你忽略这两个步骤, 那么在第二步所产生的任何修改都会触发一次重排。

有三种基本方法可以使DOM脱离文档:

  • 隐藏元素, 应用修改, 重新显示。
  • 使用文档片断(docuement fragment)在当前DOM之外构建一个子树, 再把它拷贝回文档。
  • 将原始元素拷贝到一个脱离文档的节点中,改副本, 完成后再替换原始元素。

缓存布局信息

如前文所述,浏览器尝试通过队列化修改和批量执行的方式最小化重排次数。当你查询布局信息时,比如获取偏移量(offsets)、滚动位置(scroll values)或计算出的样式值(computedsytle values)时,浏览器为了返回最新值,会刷新队列并应用所有变更。最好的做法是尽量减少布局信息的获取次数,获取后把它赋值给局部变量,然后再操作局部变量。

考虑一个例子,把myElement元素沿对角线移动,每次移动一个像素,从100像素×100像素的位置开始,到500像素x500像素的位置结束。在timeout循环体中你可以使用下面的方法:

//低效的
myElement.style.left = 1 + myElement.offsetLeft +'px'
myElement.style.top = 1 + myElement.offsetTop +'px'
if (myElement.offsetLeft >= 500) { 
	stop()
}

这种方法效率低下,因为元素每次移动时都会查询偏移量,导致浏览器刷新渲染列队而不利于优化。一个更好的方法是,获取一次起始位置的值,然后将其赋值给一个变量,比如var current = myElement.offsetleft。然后,在动画循环中,直接使用current变量而不再用偏移量:

current++ 
myElement.style.left = current+'px'
myElement.style.top = current+'px'
if (current >= 500) { 
	stop()
}

让元素脱离动画流

用展开/折叠的方式来显示和隐藏部分页面是一种常见的交互模式。它通常包括展开区域的几何动画,井将页面其他部分推向下方。

一般来说,重排只影响渲染树中的一小部分,但也可能影响很大的部分,甚至整个渲染树。 浏览器所需要重排的次数越少,应用程序的响应速度就越快。因此当页面顶部的一个动画推移页面整个余下的部分时,会导致一次代价昂贵的大规模重排,让用户感到页面一顿一 顿的。渲染树中需要重新计算的节点越多,情况就会越糟。

使用以下步嘱可以避免页面中的大部分重排:

  1. 使用绝对位置定位页面上的动画元素, 将其脱离文档流。
  2. 让元素动起来。 当它扩大时, 会的时覆盖部分页面。 但只是页面一个区域的重绘过程, 不会产生重排并重绘页面的大部分内容。
  3. 当动画结束时恢复定位, 从而只会下移一次文档的其他元素。

IE和:hover

从IE 7开始,IE允许在任何元素(严格模式下)上使用:hover这个 css 伪选择器。 然而,如果你有大量元素使用了:hover, 那么会降低响应速度。 此问题在IE8中更为明显。

例如,如果你创建一个5列和500~1000行的表格,并使用tr:hover改变背景色来高亮显示鼠标所在的当前行, 当鼠标在表格上移动时, 性能会降低。 高亮过程会变慢, CPU使用率会提高到80%~90%。所以在元素很多时应避免使用这种效果,比如很大的表格或很长的列表。文章来源地址https://www.toymoban.com/news/detail-846551.html

到了这里,关于【DOM】重绘与重排详解及在性能优化中的应用的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 杰卡德相似度(Jaccard)详解及在UserCF中的应用

    1、杰卡德相似度(Jaccard) 这个是衡量两个 集合 的相似度一种指标。 两个集合A和B的交集元素在A,B的并集中所占的比例,称为两个集合的杰卡德相似系数,用符号J(A,B)表示 另一种表示的方法: jaccard系数衡量维度相似性 jaccard系数很适合用来分析多个维度间的相似性,也多被

    2023年04月14日
    浏览(26)
  • Android UI性能优化实战 识别绘制中的性能问题

    { super.onCreate(savedInstanceState); setContentView(R.layout.activity_overdraw_01); mInflater = LayoutInflater.from(this); mListView = (ListView) findViewById(R.id.id_listview_chats); mListView.setAdapter(new ArrayAdapter(this, -1, Droid.generateDatas()) { @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder holder =

    2024年04月15日
    浏览(30)
  • 即时通讯开发中的性能优化技巧

    即时通讯开发在如今的数字化社会中扮演着重要角色,然而,随着用户对即时通讯应用的需求不断增长,开发者们面临着使其应用保持高性能和可靠性的挑战。本文将探讨即时通讯开发中关键的性能优化技巧,帮助开发者们提升应用的用户体验和响应速度。 1. 建立高效的消息

    2024年02月10日
    浏览(25)
  • Android UI性能优化实战 识别绘制中的性能问题(1)

    { public String name; public int imageId; public String date; public String msg; public Droid(String msg, String date, int imageId, String name) { this.msg = msg; this.date = date; this.imageId = imageId; this.name = name; } public static List generateDatas() { List datas = new ArrayList(); datas.add(new Droid(“Lorem ipsum dolor sit amet, orci nullam cra”

    2024年04月13日
    浏览(33)
  • JavaWeb应用中的安全与性能优化

    JavaWeb应用是现代互联网应用的核心组成部分,它们为用户提供了丰富的功能和服务。然而,JavaWeb应用在安全和性能方面面临着巨大的挑战。这篇文章将探讨JavaWeb应用中的安全与性能优化,并提供一些实用的最佳实践。 JavaWeb应用的安全性和性能对于企业和用户来说都是至关

    2024年02月20日
    浏览(23)
  • FPGA上基于Verilog的TCP乱序重排算法实现及性能评估

    基于fpga的tcp乱序重排算法实现,通过verilog实现适用于fpga的tcp乱序重排算法,并通过实际数据测试验证。 代码里包含注释,可以明白每个模块的含义。 采用自创的乱序重排算法,易于在硬件中实现。 该算法和工程可用于实际应用、算法设计、研究学习。 提供测试用的抓包文

    2024年04月13日
    浏览(29)
  • 提升应用性能的关键步骤——UniApp性能优化策略与技巧详解

    「作者主页」 :雪碧有白泡泡 「个人网站」 :雪碧的个人网站 chatgpt体验地址 描述:代码压缩和混淆是常用的性能优化手段。通过减小JavaScript、CSS和HTML文件的大小,可以降低加载时间和网络传输。 解释: 在构建UniApp应用时,确保开启代码压缩和混淆选项。 使用工具(如

    2024年02月03日
    浏览(28)
  • 关于 React 性能优化和数栈产品中的实践

    我们是袋鼠云数栈 UED 团队,致力于打造优秀的一站式数据中台产品。我们始终保持工匠精神,探索前端道路,为社区积累并传播经验价值。 本文作者:的卢 在日常开发过程中,我们会使用很多性能优化的 API ,比如像使用 memo 、 useMemo 优化组件或者值,再比如使用 shouldCo

    2024年02月08日
    浏览(29)
  • MySql 性能优化神器之 explain 详解

    目录 一. 前言 二. explain 详解 2.1. 概念 2.2. 数据准备 2.3. id 2.3.1. id 相同,执行顺序由上至下 2.3.2. id 不同,数字越大优先级越高 2.3.3. id 存在相同的和不同的 2.4. select_type 2.5. table 2.6. partitions 2.7. type 2.7.1. system 2.7.2. const 2.7.3. eq_ref 2.7.4. ref 2.7.5. fulltext 2.7.6. ref_or_null 2.7.7. 

    2024年02月03日
    浏览(24)
  • Android UI性能优化 检测应用中的UI卡顿

    } }; public static LogMonitor getInstance() { return sInstance; } public boolean isMonitor() { return mIoHandler.hasCallbacks(mLogRunnable); } public void startMonitor() { mIoHandler.postDelayed(mLogRunnable, TIME_BLOCK); } public void removeMonitor() { mIoHandler.removeCallbacks(mLogRunnable); } } 我们利用了HandlerThread这个类,同样利用了Loope

    2024年04月14日
    浏览(35)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包