Checking width and setting width inside forEach loop performance

戏子无情 提交于 2019-12-24 10:48:19

问题


I have two pieces of code below

Snippet#1

const doubleWidth = (element) => {
  const width = element.offsetWidth;
  element.style.width = `${width * 2}px`;
};
button.addEventListener('click', (event) => {
  boxes.forEach(doubleWidth);
});

Snippet#2

button.addEventListener('click', (event) => {
  var widths = boxes.map(item => item.offsetWidth);
  boxes.forEach((element, index) => {
         element.style.width = `${widths[index] * 2}px`;
  });
});

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.

Here's the complete code - https://codepen.io/kushalmahajan/pen/mjXVqp?editors=0010

Update - So , let me explain a bit more

In Snippet #1, I see each time a pattern like calculate, Reset, Calculate, Reset ...so forth

In Snippet #2. That's not the case.

Please base you answers around render pipeline please


回答1:


in Snippet 1 each time you are executing 2 commands:

const width = element.offsetWidth;
element.style.width = `${width * 2}px`;

while in Snippet 2 each time you are executing only 1 command:

element.style.width = `${widths[index] * 2}px`;

Therefore I think it's natural to have more than double the time for the execution. depending on how much time it take to execute the following command:

const width = element.offsetWidth;

For a fair comparison between the 2 snippets I would suggest removing the above command from the loop and check how long it would take to execute snippet 1 in that case.

I hope that helps.




回答2:


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:

  1. forEach with immediately getting offsetWidth and setting width
  2. forEach with storing offsetWidth and the corresponding element first and then setting width it in a second forEach
  3. map with storing offsetWidth and then setting width on the elements in a forEach loop

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');
    });
};

OUTPUT:

Double Sizes ForEach: 12.341064453125ms
Double Sizes ForEach 2: 0.539794921875ms
Double Sizes Map: 0.590087890625ms

NOTES:

  • what forces layout/reflow
  • article on layout performance issues and layout thrashing

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.



来源:https://stackoverflow.com/questions/51609846/checking-width-and-setting-width-inside-foreach-loop-performance

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!