检查每个循环性能的宽度和内部设置宽度 [英] Checking width and setting width inside forEach loop performance
问题描述
我下面有两段代码
代码段1
const doubleWidth = (element) => {
const width = element.offsetWidth;
element.style.width = `${width * 2}px`;
};
button.addEventListener('click', (event) => {
boxes.forEach(doubleWidth);
});
代码段2
button.addEventListener('click', (event) => {
var widths = boxes.map(item => item.offsetWidth);
boxes.forEach((element, index) => {
element.style.width = `${widths[index] * 2}px`;
});
});
与片段2(仅18.4ms)相比,片段1有48ms的时间.为什么会这样?
Snippet #1 has a lot 48ms compared to snippet #2 which is only 18.4ms. Why is that behaviour?
毕竟,我仍在进行两项计算和设置操作(哪些是强制性的重熔).
After all, I am still doing two operation of calculating and settings ( which forcers reflows ) each.
这是完整的代码- https://codepen .io/kushalmahajan/pen/mjXVqp?editors = 0010
更新-所以,让我多解释一下
Update - So , let me explain a bit more
在代码片段1中,我每次都会看到诸如计算,重置,计算,重置...之类的模式
In Snippet #1, I see each time a pattern like calculate, Reset, Calculate, Reset ...so forth
在代码段2中.事实并非如此.
In Snippet #2. That's not the case.
请根据您的渲染管道为您提供答案
推荐答案
我不确定原因,但显然如果您先存储offsetWidth
,则对性能而言是否使用forEach
都无关紧要或map
:这是一支钢笔来说明这种行为.
I'm not sure about the reason, but apparently if you store offsetWidth
first, it doesn't matter performance-wise whether you use forEach
or map
: here's a pen to illustrate this behavior.
您可以看到我对三个组合进行了计时:
You can see that I timed three combinations:
-
forEach
,并立即获取offsetWidth
并设置width
-
forEach
,首先存储offsetWidth
和相应的元素,然后在第二个forEach
中设置其宽度
-
map
并存储offsetWidth
,然后在forEach
循环中的元素上设置width
forEach
with immediately gettingoffsetWidth
and settingwidth
forEach
with storingoffsetWidth
and the corresponding element first and then setting width it in a secondforEach
map
with storingoffsetWidth
and then settingwidth
on the elements in aforEach
loop
选项 2.和 3.在性能上基本相同.从这一点来看,我要说获得offsetWidth
和设置width
的组合是一个性能瓶颈.真的不能告诉你更多,对不起!
Option 2. an 3. were basically the same performance wise. Judging from that, I would say that the combination of getting offsetWidth
and setting width
is a performance bottleneck. Can't really tell you much more than that, sorry!
window.onload = () => {
const boxes = Array.from(document.querySelectorAll('.box'));
document.getElementById('double-sizes-forEach')
.addEventListener('click', (event) => {
console.time('Double Sizes ForEach');
boxes.forEach((element, index) => {
const width = element.offsetWidth;
element.style.width = `${width * 2}px`;
});
console.timeEnd('Double Sizes ForEach');
});
document.getElementById('double-sizes-forEach-2')
.addEventListener('click', (event) => {
console.time('Double Sizes ForEach 2');
let a = [];
boxes.forEach((element, index) => {
a.push([element, element.offsetWidth]);
});
a.forEach(([e, w]) => {
e.style.width = `${w * 2}px`;
});
console.timeEnd('Double Sizes ForEach 2');
});
document.getElementById('double-sizes-map')
.addEventListener('click', (event) => {
console.time('Double Sizes Map');
var widths = boxes.map(item => item.offsetWidth);
boxes.forEach((element, index) => {
element.style.width = `${widths[index] * 2}px`;
});
console.timeEnd('Double Sizes Map');
});
};
输出:
Double Sizes ForEach: 12.341064453125ms
Double Sizes ForEach 2: 0.539794921875ms
Double Sizes Map: 0.590087890625ms
注释:
- what forces layout/reflow
- article on layout performance issues and layout thrashing
第二篇文章指出,您应始终将更改样式(例如设置width
)和进行测量(例如获取offsetWidth
)分开,以免布局出现问题.似乎也是代码中的问题.
The second article argues that you should always separate changing style (e.g. setting width
) and taking measurements (e.g. getting offsetWidth
) to avoid layout thrashing. Seems that's the problem in your code as well.
这篇关于检查每个循环性能的宽度和内部设置宽度的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!