显示:for 循环中的 none 及其对回流的影响
display: none in a for loop and its affect on reflow
我今天在阅读一些代码时遇到了这个 for 循环:
for (i=0; i<100; i++){
document.getElementById(elem + i).style.display="none";
}
我才刚刚开始了解浏览器回流;但是,我目前的理解是,此循环导致它设置显示的 100 个元素中的每一个元素都发生回流 none。
这个循环对 DOM 有什么影响?这真的有我想的那么可怕吗?
渲染新页面时使用此代码。
对于您显示的代码,不,不是
Chrome Developer Tools 时间轴是测试此类问题的好方法,尤其是因为“我认为的那样可怕”是相当主观的。
我 运行 测试了您在此 fiddle 中 post 编写的代码。将此称为 测试 1。
- 请注意,我在测试中使用了 1000 个元素,而不是 100 个元素。
为了控制,我通过使用 this fiddle 中的代码在动画帧中将包装器元素设置为 display:'none'
来有效地隐藏元素。将此称为 测试 2。
- 在测试 1 中,渲染花费了 17.6 毫秒。
- 在测试 2 中,渲染花费了 1.5 毫秒。
所以经验答案是肯定的,与替代(理想)方法相比,测试代码需要 10 倍以上的计算时间来重排页面布局。在不了解提取它的代码的情况下,很难说所使用的方法是否合适或必要。
例如,如果要隐藏的元素没有整齐地包裹在它们自己的包装器中 <div>
,优化就很困难。避免 for
循环的策略是为元素分配一个“hideable
” class,并设置一个 CSS 规则,如 wrapper.hideChildren > .hideable { display:none; }
。然后,当我们将 class "hideChildren
" 分配给包装器时,标记的元素被隐藏。 Using this strategy,当包装器从 DOM 在操作之前,然后重新附加。换句话说,for
循环可能不会导致那么多的性能损失。请记住,17 毫秒大约是每秒 60 帧的 1 帧动画。
如果您检查此 post 末尾的屏幕截图,您会注意到即使在 测试 1 中,所有“脚本”(for
-loop)发生在所有“rending”(重新流)之前。因此,如果您的问题是“浏览器是否会在循环的每次迭代中交替执行脚本和渲染”,那么答案是 否 ,至少在 Chrome 50.
至于评论中fridge_light的link,linked文档从未声明设置display:none
不会触发回流;它只包含它 link 播放的视频中的图表,没有图例。设置 display:none
将 改变布局:文档的高度可能会改变,隐藏元素下方的元素将移近文档的顶部,元素与隐藏元素将在线移动,浮动元素将改变其周围的位置,等等。因此浏览器必然会进行一些计算。
您的问题有点混乱:DOM 不一定与页面重排有关。例如,重新调整浏览器 window 的大小可能会触发重新流动而根本不会影响 DOM!将 display
设置为 none
会从页面 layout/flow 中删除一个元素,但将其保留在 DOM.
测试 1
测试 2
我今天在阅读一些代码时遇到了这个 for 循环:
for (i=0; i<100; i++){
document.getElementById(elem + i).style.display="none";
}
我才刚刚开始了解浏览器回流;但是,我目前的理解是,此循环导致它设置显示的 100 个元素中的每一个元素都发生回流 none。
这个循环对 DOM 有什么影响?这真的有我想的那么可怕吗?
渲染新页面时使用此代码。
对于您显示的代码,不,不是
Chrome Developer Tools 时间轴是测试此类问题的好方法,尤其是因为“我认为的那样可怕”是相当主观的。
我 运行 测试了您在此 fiddle 中 post 编写的代码。将此称为 测试 1。
- 请注意,我在测试中使用了 1000 个元素,而不是 100 个元素。
为了控制,我通过使用 this fiddle 中的代码在动画帧中将包装器元素设置为 display:'none'
来有效地隐藏元素。将此称为 测试 2。
- 在测试 1 中,渲染花费了 17.6 毫秒。
- 在测试 2 中,渲染花费了 1.5 毫秒。
所以经验答案是肯定的,与替代(理想)方法相比,测试代码需要 10 倍以上的计算时间来重排页面布局。在不了解提取它的代码的情况下,很难说所使用的方法是否合适或必要。
例如,如果要隐藏的元素没有整齐地包裹在它们自己的包装器中 <div>
,优化就很困难。避免 for
循环的策略是为元素分配一个“hideable
” class,并设置一个 CSS 规则,如 wrapper.hideChildren > .hideable { display:none; }
。然后,当我们将 class "hideChildren
" 分配给包装器时,标记的元素被隐藏。 Using this strategy,当包装器从 DOM 在操作之前,然后重新附加。换句话说,for
循环可能不会导致那么多的性能损失。请记住,17 毫秒大约是每秒 60 帧的 1 帧动画。
如果您检查此 post 末尾的屏幕截图,您会注意到即使在 测试 1 中,所有“脚本”(for
-loop)发生在所有“rending”(重新流)之前。因此,如果您的问题是“浏览器是否会在循环的每次迭代中交替执行脚本和渲染”,那么答案是 否 ,至少在 Chrome 50.
至于评论中fridge_light的link,linked文档从未声明设置display:none
不会触发回流;它只包含它 link 播放的视频中的图表,没有图例。设置 display:none
将 改变布局:文档的高度可能会改变,隐藏元素下方的元素将移近文档的顶部,元素与隐藏元素将在线移动,浮动元素将改变其周围的位置,等等。因此浏览器必然会进行一些计算。
您的问题有点混乱:DOM 不一定与页面重排有关。例如,重新调整浏览器 window 的大小可能会触发重新流动而根本不会影响 DOM!将 display
设置为 none
会从页面 layout/flow 中删除一个元素,但将其保留在 DOM.