Layout reflow can be a performance bottleneck. Let's see how to identify it in the browser and what causes the reflow.
In normal process, "Style & Layout" happens after "Javascript".
Here we can consider "Javascript" part is doing "DOM Mutataion" and
"Style & Layout" is doing "DOM Measurement".
"Layout reflow": "Style & Layout" happens during "Javascirpt". Or we can also say "measurement happens after Mutation".
You can identitfy the "Layout reflow":
In this code, it looks like:
function addItem() { const newEl = document.createElement("div") // Mutate wrapper.appendChild(newEl) // Measurement height = wrapper.getBoundingClientRect().height }
Solve layout reflow
One possible way is move "Measurement" before "Mutate":
function addItem() { const newEl = document.createElement("div") // Measurement height = wrapper.getBoundingClientRect().height // Mutate wrapper.appendChild(newEl) }
Second way: if it is not possible to reverse the order of code, we can do: "setTimeout":
function addItem() { const newEl = document.createElement("div"); // Mutate wrapper.appendChild(newEl); setTimeout(() => { // Measurement height = wrapper.getBoundingClientRect().height; }, 0); }
Or better, using 'requestAnimationFrame'
function addItem() { const newEl = document.createElement("div"); // Mutate wrapper.appendChild(newEl); requestAnimationFrame(() => { // Measurement height = wrapper.getBoundingClientRect().height; }); }
Solving layout thrashing by caching measured value
Layout thrashing is when we force the browser to measure the DOM multiple times during a synchronous process. This can have major performance consequences. In this lesson we will see the case in which measuring a static value from the DOM can cause layout thrashing - and it can be solved by caching the value.
In short, do multi layout reflow during one single process
All the red block is showing that there is a big performance issue.
From the code:
function compareWidths() { // repeat "measure" - "mutate" - "measure" -... for (let i = 0; i < wrapper.childElementCount; i++) { // measure const wrapperWidth = wrapper.offsetWidth; // mutate wrapper.children[i].style.width = wrapperWidth; } }
We can solve the problem by moving following code out of for loop, because it always getting the same value
const wrapperWidth = wrapper.offsetWidth;
function compareWidths() { // measure const wrapperWidth = wrapper.offsetWidth; for (let i = 0; i < wrapper.childElementCount; i++) { // mutate wrapper.children[i].style.width = wrapperWidth; } }
Another way to solve the problem is using decounce:
const debouncedSubmitNewHeightEvent = _.debounce(submitNewHeightEvent, 50);
So that multi calculation will group into only one calculation.