for 循环中的 display: none 及其对回流的影响

emr*_*den 1 javascript css reflow

我今天读了一些代码,发现了这个 for 循环:

for (i=0; i<100; i++){
    document.getElementById(elem + i).style.display="none";
}
Run Code Online (Sandbox Code Playgroud)

我才刚刚开始了解浏览器重排;然而,我目前的理解是,这个循环导致它设置为不显示的 100 个元素中的每一个元素都发生回流。

这个循环对 DOM 有何影响?这真的像我想象的那么可怕吗?

此代码在渲染新页面时使用。

A. *_*dor 5

Chrome开发者工具时间线是测试此类问题的好方法,特别是因为“像我认为的那样可怕”是相当主观的。

我对您在此小提琴中发布的代码进行了测试。将此称为测试 1

  • 请注意,我在测试中使用了 1000 个元素,而不是 100 个。

为了进行控制,我通过使用此fiddledisplay:'none'中的代码将包装器元素设置在动画帧中来有效地隐藏元素。将此称为测试 2

  • 测试 1中,渲染花费了17.6 毫秒
  • 测试 2中,渲染花费了1.5 毫秒

因此,经验答案是肯定的,与替代(理想)方法相比,测试的代码需要超过 10 倍的计算时间来重排页面布局。如果不了解提取该代码的更多信息,就很难说所使用的方法是否合适或必要。

例如,如果要隐藏的元素没有整齐地包装在它们自己的包装器中<div>,那么优化就很困难。避免循环的策略for是为元素分配一个“ hideable”类,并设置一个 CSS 规则,如wrapper.hideChildren > .hideable { display:none; }. 然后,当我们将类“ hideChildren”分配给包装器时,标记的元素将被隐藏。使用这种策略,我只能将渲染时间降低到15 毫秒,或者在操作之前将包装器与 DOM 分离并在操作之后重新附加时将渲染时间降低到10 毫秒。换句话说,for循环可能不会造成太大的性能损失。请记住,17 毫秒大约相当于每秒 60 帧的动画的 1 帧。

如果您检查本文末尾的屏幕截图,您会注意到,即使在测试 1中,所有“脚本”(循环的执行for)都发生在所有“渲染”(重新流)之前。因此,如果您的问题是“浏览器是否会在循环的每次迭代中交替编写脚本和渲染”,那么答案是否定的,至少在 Chrome 50 中是这样。

至于评论中的冰箱灯链接,链接文档从未声明设置display:none不会触发回流;它只包含链接到的视频中的图表,没有图例。设置display:none 改变布局:文档的高度可能会改变,隐藏元素下方流动的元素将移动到更靠近文档顶部的位置,与隐藏元素内联的元素将内联移动,浮动元素将改变其周围的位置等等。所以浏览器必然会完成一些计算。

你的问题有点困惑:DOM 不一定与页面重新流相关。例如,重新调整浏览器窗口的大小可能会触发重新流,而根本不会影响 DOM!设置displaynone从页面布局/流程中删除元素,但将其保留在 DOM 中。

测试1测试1

测试2测试3

  • 这是一个非常好的答案,是的,您对链接文章和随附图表的看法是正确的。作者的说法“从上表可以清楚地看出,并非所有 JavaScript 中样式的更改都会导致所有浏览器中的回流”是误导性的 - “display”属性缺少时间意味着测试结果小于 1其次,并不是说没有发生回流焊。无论如何,演讲本身的相关背景可以在 28 分钟左右找到:https://www.youtube.com/watch?v=aJGC0JSlpPE&amp;t=1700 (2认同)