When the DOM changes affect the geometric properties of the element (width, height changes, etc.) the
browser needs to recalculate the geometric properties
of the element and the geometric properties of other elements in the page may be affected . The
rendering tree changes, that is, re- The process of constructing a RenderTree rendering tree
is called reflow
If the DOM change only affects the background color and other non-geometric properties
, then a repaint occurs instead of a reflow
because the layout has not changed.
Page redraw and reflow will affect performance (redraw is better), try to avoid or reduce reflow
trigger rearrangement
Changes in page layout and element geometry can cause reflows Reflow
occurs in the following situations
- page initial rendering
- Add/remove visible DOM elements
- change element position
- Change element dimensions (width, height, margins, borders, etc.)
- Change element content (text or image, etc.)
- Change window size
The scope and degree of rearrangement will be different under different conditions.
In some cases, the entire page may even be rearranged, such as sliding the scroll bar.
Browser Optimization: Render Queue
- div.style.left = '10px';
- div.style.top = '10px';
- div.style.width = '20px';
- div.style.height = '20px';
As above, the left, top, width, and height properties of the element are modified to
meet the conditions for our reflow. In
theory, 4 reflows will occur,
but in fact, only 1 reflow will occur.
This is because our modern browsers have rendering Queue mechanism
When I change a style of an element, it will cause the browser to reorder or redraw.
It will enter a rendering queue
and then the browser will continue to look down. If there is a style modification below,
it will also enter the queue
until there is no style below . Modify the
browser to optimize the rearrangement process according to the batch execution of the rendering queue, and modify the style to optimize
the 4 times of rearrangement to 1 time.
div.style.left = '10px';
console.log(div.offsetLeft);
div.style.top = '10px';
console.log(div.offsetTop);
div.style.width = '20px';
console.log(div.offsetWidth);
div.style.height = '20px';
console.log(div.offsetHeight);
As above, 4 rearrangements of
offsetLeft/Top/Width/Height will force the queue to be refreshed and require the style modification task to be executed immediately.
This makes sense.
After all, the browser is not sure whether you will modify the same style in the next code in
order to Guaranteed to get the correct value, it has to execute the render queue immediately to trigger the reorder
The following properties or methods flush the render queue
- offsetTop、offsetLeft、offsetWidth、offsetHeight
- clientTop、clientLeft、clientWidth、clientHeight
- scrollTop、scrollLeft、scrollWidth、scrollHeight
- getComputedStyle()(IE中currentStyle)
In the process of modifying the style, we should try to avoid using the above properties
Performance optimization for redraw and reflow
Separate read and write operations
Knowing the principle, we can optimize the above code
- div.style.left = '10px';
- div.style.top = '10px';
- div.style.width = '20px';
- div.style.height = '20px';
- console.log(div.offsetLeft);
- console.log(div.offsetTop);
- console.log(div.offsetWidth);
- console.log(div.offsetHeight);
There is only one rearrangement, and the reason is believed to be clear
to everyone. Move all read operations after all write operations
style change
or the code where we originally modified the style
div.style.left = '10px';
div.style.top = '10px';
div.style.width = '20px';
div.style.height = '20px';
As above, although modern browsers have an optimization mechanism for rendering queues,
ancient browsers are still inefficient, triggering 4 reflows
. Even so, we can still make optimizations.
We need the cssText property to merge all style changes
div.style.cssText = 'left:10px;top:10px;width:20px;height:20px;';
As above, only need to modify the DOM once and process it together,
only triggering 1 reflow
and only one line of code, see looks relatively clean
Note that cssText will overwrite the existing interline style
. If you want to keep the original interline style, the following
div.style.cssText += ';left:10px;';
In addition to cssText, we can also modify the style by modifying the class name, as follows
div.className = 'new-class';
this method is maintainable and can also help us avoid
the small performance impact of the display code , changing the class needs to check the cascading style, but conforming to the BEM standard can better decouple and increase maintainability. It is recommended to write
div.className = 'js-class';
Cache layout information
I think caching is a panacea, and any performance optimization is indispensable
. div.style.left = div.offsetLeft + 1 + 'px';
div.style.top = div.offsetTop + 1 + 'px';
As above, this kind of reading Executing the write operation after the operation causes 2 rearrangements of the
cache, which can be optimized
var curLeft = div.offsetLeft;
var curTop = div.offsetTop;
div.style.left = curLeft + 1 + 'px';
div.style.top = curTop + 1 + 'px';
As above, this is also equivalent to separate reading Write operations are
optimized to 1 rearrangement
Element batch modification
Now we want to add a lot of li to the ul in a loop
(if the ul doesn't already exist, the best way is to add the li to the ul in a loop, and then add the ul to the document, 1 rearrangement)
var ul = document.getElementById( 'demo');
for(var i = 0; i < 1e5; i++){
var li = document.createElement('li');
var text = document.createTextNode(i);
li.appendChild(text); ul. appendChild(li);
}
我可以做出下面的优化
var ul = document.getElementById('demo');
ul.style.display = 'none';
for(var i = 0; i < 1e5; i++){
var li = document.createElement('li');
var text = document.createTextNode(i);
li.appendChild(text); ul.appendChild(li);
}
ul.style.display = 'block';
var ul = document.getElementById('demo');
var frg = document.createDocumentFragment();
for(var i = 0; i < 1e5; i++){
var li = document.createElement('li');
var text = document.createTextNode(i);
li.appendChild(text); frg.appendChild(li);
}
ul.appendChild(frg);
var ul = document.getElementById('demo');
var clone = ul.cloneNode(true);
for(var i = 0; i < 1e5; i++){
var li = document.createElement('li');
var text = document.createTextNode(i);
li.appendChild(text); clone.appendChild(li);
}
ul.parentNode.replaceChild(clone,ul);
The principle of the above method to reduce redraw and rearrangement is very simple
- Element out of document
- change style
- Element regression documentation
And changing the element uses
Hidden Element
Document Fragment
Clone Element respectively