A byte interview question refreshed my cognition, and learned new knowledge, happy.

I said at the beginning that the answer is 3 times each, because you get an offsetWidth once, and then you change the style once.

But it turns out that offsetWidth triggers reordering because the render queue is refreshed. In this case, the render queue was empty, so no reordering was triggered. So twice.

Render queue = render queue = render queue = render queue It doesn’t matter if you don’t understand the render queue, look down and you will understand.

There are, of course, antique and modern browsers. Modern browsers (i.e., those with render queues) should do it once, and antique browsers should do it twice

I. What is redrawing and rearrangement

After downloading all the components of the page — HTML tags, JavaScript, CSS, images — the browser parses and generates two internal data structures — the DOM tree and the render tree.

The DOM tree represents the page structure, and the render tree represents how the DOM nodes are displayed. Each node in the DOM tree that needs to be displayed has at least one corresponding node in the render tree (the hidden DOM element disply none has no corresponding node in the render tree). Nodes in the render tree are called “frames” or “boxes,” which conform to the definition of the CSS model, understanding a page element as a box with padding, margins, borders, and positions. Once the DOM and render tree are built, the browser begins to display (draw) page elements.

When a DOM change affects an element’s geometry (width or height), the browser needs to recalculate the element’s geometry, as well as the geometry and position of other elements. The browser invalidates the affected portion of the render tree and reconstructs the render tree. This process is called rearrangement. When the rearrangement is complete, the browser redraws the affected parts to the screen, a process called redraw. Because of the browser’s flow layout, calculations of the render tree are usually done only once. With the exception of table and its inner elements, it can take multiple computations to determine the attributes of its nodes in the rendered tree, often taking three times as long as the equivalent element. This is one reason why we should avoid using tables for layout.

Not all DOM changes affect geometric properties; for example, changing the background color of an element does not affect the width or height of the element; in this case, only redraw will occur.

Whether pages are redrawn or rearranged, they affect performance

How to trigger rearrangement

Changes in page layout and element geometry can cause rearrangements in the following cases

  • Initial page rendering
  • Add/remove visible DOM elements
  • Change element position
  • Change element dimensions (width, height, inside and outside margins, borders, etc.)
  • Changing element content (text, images, etc.)
  • Change window size

The extent and extent of rearrangement will be different under different conditions

In some cases, it even rearranges the entire page, such as sliding the scroll bar

Third, browser optimization

Such as:

Suppose I want to change the style of a div with JS

div.style.left = '10px';
div.style.top = '10px';
div.style.width = '10px';
div.style.height = '10px';
Copy the code

We have modified the elements of the left, top, width and height attributes, meet our rearrangement conditions, four rearrangement will happen in theory, but in fact will only happen once rearrangement, because our modern browsers render queue mechanism, when I change the elements of a style can lead to browser rearrangement or redrawn “, it will enter a render queue, and then the browser will look down, and if there are any style changes below, it will queue again, until there are no style changes below, and the browser will execute the render queue in batches to optimize the rearrangement process, and modify the style as well, so that instead of 4 rearrangements, it will optimize the rearrangement to 1

But, when we write the following code:

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); Copy the code

Is it still a rearrangement?

Obviously not! Four rearrangements have occurred at this point!

The browser has a render queue optimization mechanism. Why four times?

It related to the offsetLeft/Top/Width/Height

OffsetTop, offsetLeft, offsetWidth, offsetHeightClientTop, clientLeft, clientWidth, clientHeightScrollTop, scrollLeft, scrollWidth, scrollHeightGetComputedStyle () (currentStyle in IE)Copy the code

These force a queue refresh and require the style change task to be executed immediately

Because the browser is not sure if the same style will be changed in the following code, it has to perform the render queue trigger reorder immediately to get the correct current time value!!

Redraw and rearrange performance optimization

1. Separate read and write operations

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); Copy the code

That’s only 1 rearrangement!

2. Style set changes

The same code that we originally modified the style

div.style.left = '10px';
div.style.top = '10px';
div.style.width = '20px';
div.style.height = '20px';
Copy the code

Although modern browsers have optimization mechanisms for rendering queues, antique browsers are still inefficient, triggering 4 rearrangements. Even so, we can still make optimization, and we need cssText properties to incorporate all style changes

div.style.cssText = 'left:10px; top:10px; width:20px; height:20px; ';
Copy the code

This requires only one DOM change, only one rearrangement, and only one line of code

In addition to cssText, we can also make style changes by changing the class name

div.className = 'new-class';
Copy the code

This approach is maintainable and helps us avoid explicit code, but it takes a little bit of performance

3. Cache layout information

div.style.left = div.offsetLeft + 1 + 'px';
div.style.top = div.offsetTop + 1 + 'px';
Copy the code

This type of write after the read operation causes two rearrangements

The cache can be optimized

var curLeft = div.offsetLeft;
var curTop = div.offsetTop;
div.style.left = curLeft + 1 + 'px';
div.style.top = curTop + 1 + 'px';
Copy the code

This is equivalent to a separate read and write operation, optimized for a single rearrangement

4. Batch operation of elements

Now we want to loop in a lot of Li to ul (if UL doesn’t already exist, the best way is to loop in li to UL and then ul to the document, once again)

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); } Copy the code

I can make the following optimization

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); Copy the code

The principle of reducing redraw and rearrangement in the above method is simple

  • Element out of document
  • Change the style
  • Element regression document

Changing elements uses hidden elements, document fragments, and cloned elements, respectively

This article is formatted using MDNICE