循环导致强制回流,而相同的代码没有循环不会导致回流
Looping causes forced reflow while the same code doesn't cause reflow without loop
当我们使用循环时,我发现了一个奇怪的强制回流案例。 Example here
在第一种情况下,我循环遍历了 200 个元素并使用 for 循环更改其 class。
function resize1(){
let children = parent1.children;
clicked2 = !clicked2;
for(let i=0;i<200;i++){
let child = children[i];
let { width } = window.getComputedStyle(child);
isLarge = clicked2 ? i % 2 === 0 : i % 2=== 1;
if(isLarge){
child.classList.add('large');
child.classList.remove('small');
}
else{
child.classList.add('small');
child.classList.remove('large');
}
// size = window.getComputedStyle(child).margin;
}
}
我没有循环,而是再次遍历每个子元素并更改了相同的 class。
let width, isLarge, i =0, child;
child = parent.children[i];
width = window.getComputedStyle(child);
isLarge = clicked ? i % 2 === 0 : i % 2=== 1;
if(isLarge){
child.classList.add('large');
child.classList.remove('small');
}
else{
child.classList.add('small');
child.classList.remove('large');
}
i++;
child = parent.children[i];
width = window.getComputedStyle(child);
isLarge = clicked ? i % 2 === 0 : i % 2=== 1;
if(isLarge){
child.classList.add('large');
child.classList.remove('small');
}
else{
child.classList.add('small');
child.classList.remove('large');
}
i++;
(*200 个元素)
我知道这种情况很奇怪,但是当我检查性能时,第二种情况在 chrome 开发工具中花费的时间较少,并且回流也仅在循环情况下发生。
答案与循环与不循环完全无关,而与您的使用方式有关 window.getComputedStyle()
。
This handy gist 概述了哪些 JavaScript 属性和方法将强制 layout/reflow.
window.getComputedStyle() will force layout in one of 3 conditions:
The element is in a shadow tree
There are media queries (viewport-related ones). Specifically, one of the following:
The property requested is one of the following:
height
, width
现在,在你的代码的循环版本中,你有这个:
let { width } = window.getComputedStyle(child);
但是在代码的 非 循环版本中,您有:
width = window.getComputedStyle(child);
有什么区别? width = window.getComputedStyle(child)
创建对计算样式对象的引用,但它 不 访问 width
属性。您已经(可能错误地)创建了一个变量 width
,它 不是 请求宽度 属性 而是计算样式对象本身,它本身不是足以强制布局。
然而,let { width } = window.getComputedStyle(child)
添加了将 width
属性 解构到变量声明的额外步骤,有效地访问 属性 并强制布局 你的for
循环的每次迭代。
您可以在性能时间线 (Safari) 中看到 let { width } = window.getComputedStyle(child)
导致的额外强制布局:
如果您修改代码的非循环版本以访问所有 200 种情况下 getComputedStyle()
的 width
属性,您将在非循环中获得相同的强制布局循环部分:
或者,您可以简单地删除对 window.getComputedStyle()
的所有使用,因为在您的代码的当前版本中它没有用于任何用途,并完全消除强制布局。
当我们使用循环时,我发现了一个奇怪的强制回流案例。 Example here
在第一种情况下,我循环遍历了 200 个元素并使用 for 循环更改其 class。
function resize1(){
let children = parent1.children;
clicked2 = !clicked2;
for(let i=0;i<200;i++){
let child = children[i];
let { width } = window.getComputedStyle(child);
isLarge = clicked2 ? i % 2 === 0 : i % 2=== 1;
if(isLarge){
child.classList.add('large');
child.classList.remove('small');
}
else{
child.classList.add('small');
child.classList.remove('large');
}
// size = window.getComputedStyle(child).margin;
}
}
我没有循环,而是再次遍历每个子元素并更改了相同的 class。
let width, isLarge, i =0, child;
child = parent.children[i];
width = window.getComputedStyle(child);
isLarge = clicked ? i % 2 === 0 : i % 2=== 1;
if(isLarge){
child.classList.add('large');
child.classList.remove('small');
}
else{
child.classList.add('small');
child.classList.remove('large');
}
i++;
child = parent.children[i];
width = window.getComputedStyle(child);
isLarge = clicked ? i % 2 === 0 : i % 2=== 1;
if(isLarge){
child.classList.add('large');
child.classList.remove('small');
}
else{
child.classList.add('small');
child.classList.remove('large');
}
i++;
(*200 个元素) 我知道这种情况很奇怪,但是当我检查性能时,第二种情况在 chrome 开发工具中花费的时间较少,并且回流也仅在循环情况下发生。
答案与循环与不循环完全无关,而与您的使用方式有关 window.getComputedStyle()
。
This handy gist 概述了哪些 JavaScript 属性和方法将强制 layout/reflow.
window.getComputedStyle() will force layout in one of 3 conditions:
The element is in a shadow tree
There are media queries (viewport-related ones). Specifically, one of the following:
The property requested is one of the following:
height
,width
现在,在你的代码的循环版本中,你有这个:
let { width } = window.getComputedStyle(child);
但是在代码的 非 循环版本中,您有:
width = window.getComputedStyle(child);
有什么区别? width = window.getComputedStyle(child)
创建对计算样式对象的引用,但它 不 访问 width
属性。您已经(可能错误地)创建了一个变量 width
,它 不是 请求宽度 属性 而是计算样式对象本身,它本身不是足以强制布局。
然而,let { width } = window.getComputedStyle(child)
添加了将 width
属性 解构到变量声明的额外步骤,有效地访问 属性 并强制布局 你的for
循环的每次迭代。
您可以在性能时间线 (Safari) 中看到 let { width } = window.getComputedStyle(child)
导致的额外强制布局:
如果您修改代码的非循环版本以访问所有 200 种情况下 getComputedStyle()
的 width
属性,您将在非循环中获得相同的强制布局循环部分:
或者,您可以简单地删除对 window.getComputedStyle()
的所有使用,因为在您的代码的当前版本中它没有用于任何用途,并完全消除强制布局。