Web Performance – Optimizing DOM operations (rearrange and redraw)

The Document Object Model (DOM) is a language-independent application programming interface. In browsers, DOM interfaces are implemented in the JavaScript language to manipulate elements in the browser page, making DOM an important part of JavaScript

In rich client web applications, UI changes on the interface are implemented through DOM manipulation, not through the traditional page refresh.

Although DOM provides a rich interface for external invocation, the cost of DOM operation is very high, and the performance bottleneck of front-end code is mostly focused on DOM operation. One of the main concerns of front-end performance optimization is DOM operation optimization.

The general principle of DOM manipulation optimization is to minimize DOM manipulation and avoid large areas of rearrangement and redrawing

Why do DOM operations affect performance?

  • In the browser, the DOM implementation is separate from the ECMAScript implementation.
  • In Chrome, DOM and rendering are handled using WebCore in WebKit, but ECMAScript is implemented in the V8 engine, and the situation is similar in other browsers.
    • Invoking the DOM interface through JavaScript code is equivalent to the interaction of two separate modules. Such cross-module calls have high performance costs compared to calls in the same module.

DOM manipulation actually has the biggest impact on performance because it causes repaint and reflow in the browser

Reflow and Repaint

Background: To give the reader a better understanding of how redraw and rearrange can affect performance, a brief description of how the browser renders.

  • From downloading the document to rendering the page, the browser builds a DOM tree by parsing the HTML document, parsing the CSS to generate a CSS rule tree.
  • The render tree is then built from the DOM tree and the CSS rule tree, where CSS matches HTML elements against selectors.
    • The render tree contains style attributes such as the size and margins of each element. The render tree does not contain hidden elements and invisible elements such as the head element.
  • Finally, the browser calculates the location of each element based on its coordinates and size and draws these elements onto the page.

redraw

Refers to parts of the page to be redrawn

For example, if the color or background color is changed, the position and size of the element are not changed;

rearrangement

When the location or size of an element changes and the browser recalculates the render tree, causing part or all of the render tree to change.

  • After the render tree is rebuilt, the browser redraws the affected elements on the page.

Both are

The cost of rearrangement is much higher than the cost of painting, redrawing will affect some elements, and rearrangement may affect all elements.

The following DOM operations cause redrawing or rearrangement.

  1. Add, delete, and modify visible DOM elements.
  2. Page initialization render.
  3. Move the DOM element.
  4. Modify CSS styles to change the size of DOM elements.
  5. The DOM element content changes, making it larger.
  6. Browser window size changed.
  7. Browser window scrolling

As you can see, these are common DOM operations. Modern browsers optimize performance for rearrangement or redrawing, such as accumulating a batch of DOM operations and rearranging or redrawing them all at once.

  • But in some cases, the browser rearranges or redraws immediately.
    • For example, request the following DOM element layout information: OffsetTop/Left/Width/Height, scrollTop/Left/Width/Height, clientTop/Left/Width/Height, getComputedStyle () or currentStyle. Because these values are computed dynamically, the browser needs to finish drawing the page as quickly as possible and then compute the return value, disrupting the optimization for rearrangement or redrawing.

Optimizing DOM operations

Page redrawing or rearrangement due to DOM manipulation is inevitable, but there are some best practices you can follow to minimize the impact of rearrangement or redrawing. Here are some specific practices

1. Merge multiple DOM operations into a single operation

Common styles that frequently modify DOM elements are:

element.style.borderColor = '#f00';
element.style.borderStyle = 'solid';
element.style.borderWidth = '1px';
Copy the code

This encoding can trigger multiple rearrangements or redraws of the page due to frequent changes in the style of DOM elements

  • Modern browsers have performance optimizations for this situation that incorporate DOM manipulation, but not all browsers have such optimizations.

The recommended approach is to merge DOM operations as much as possible, and the code above can be optimized for

// Set the following parameters
element.style.Text += 'border: 1px solid #f00; ';
// Optimization2
element.className += 'empty'
Copy the code

A similar operation is to modify the content of a DOM element through the innerHTML interface. Instead of concatenating the HTML code directly through this interface, concatenate the code as a string and assign it to the innerHTML interface of the DOM element once

2. Modify the DOM elements offline or hidden

Removing or hiding DOM elements from the page flow only causes page redrawing or reordering when DOM elements are removed and added, or hidden and displayed. Manipulating DOM elements that are removed from the page layout flow does not cause page performance problems.

This approach is suitable for situations where large amounts of DOM elements need to be modified, and there are three main ways to do this.

  1. Using document fragments

    A document fragment is a lightweight Document object that is not associated with a particular page.

    You can reduce the impact of DOM manipulation on page performance by creating a document fragment, performing the necessary DOM manipulation on that fragment, and then attaching it to the page.

    The impact on page performance only exists at the end when you attach the document fragment to the page. The code looks like this:

    var fragment = document.createDocumentFragment();
    // A lot of fragment-based DOM operations.document.getElementById('myElement').appendChild(fragment)
    Copy the code
  2. Hide elements by setting the display style of the DOM element to None

    var myElement = document.getElementById('myElement');
    myElement.style.display = 'none'
    // A lot of DOM manipulation based on myElement. myElement.style.display ='block'
    Copy the code
  3. Clone DOM elements into memory

    var old = document.getElementById('myElement');
    var clone = old.cloneNode(true)
    // A lot of Clone-based DOM manipulation. old.parentNode.replaceChild(clone, old)Copy the code

conclusion

In modern browsers, performance improvements may not be noticeable because of the DOM manipulation optimizations.

However, in older browsers that still exist, these three encodings can greatly improve page rendering performance

3. Set the position property of the ANIMATED DOM element to Fixed or Absolute

Setting animated elements on a page to absolute positioning removes them from the page layout flow, thus avoiding frequent reordering of the page and only involving the reordering of the animated elements themselves.

  • This can improve the performance of the animation.

  • If setting an animation element to absolute positioning does not meet the design requirements, you can set it to absolute positioning at the beginning of the animation and restore the original positioning after the animation ends.

On many websites, there is a large display of ads at the top of the page, usually animated and folded. Without performance optimization, the performance cost of this effect is significant. Using the optimizations mentioned here, you can improve performance.

4. Take care to obtain DOM element layout information

As discussed earlier, retrieving DOM layout information has a performance cost, and if there are repeated calls, it is best to try to cache these values in local variables. Consider the following example:

for (var i = 0; i < len; i++) {
    myElements[i].style.top = targetElement.offsetTop + i*5 + 'px'
}
Copy the code

In the code above, the offsetTop value of an element is repeatedly retrieved in a loop. In fact, the offsetTop value of the element does not change in this code, resulting in unnecessary performance loss.

The optimized solution is to get the offsetTop value of the element outside the loop, compared to the previous solution, which only calls the offsetTop value of the element once. The changed code looks like this

var targetTop = targetElement.offsetTop
for (var i = 0; i < len; i++) {
    myElements[i].style.top = targetTop + i*5 + 'px'
}
Copy the code

In addition, because obtaining the layout information of DOM elements will force the browser to refresh the rendering tree, and may lead to page redrawing or rearrangement, it is necessary to avoid obtaining the layout information of DOM elements when a large number of DOM operations are performed, so that the optimization of the browser for large number of DOM operations is not damaged.

  • If you need this layout information, it is best to obtain it before DOM manipulation. Consider the following example:
var newWidth = div1.offsetWidth + 10;
div1.style.width = newWidth + 'px';
var newHeight = myElement.offsetHeight + 10; // Force a page rearrangement
myElement.style.height = newHeight + 'px'; // It will be rearranged again
Copy the code

As described above, the code will trigger the page to recalculate the render tree when it encounters information about retrieving DOM elements, causing the page to be rearranged twice.

If you get the DOM element layout information ahead of time, the browser will optimize for consecutive DOM operations, so the page will actually be rearranged once, as shown in the optimized code

var newWidth = div1.offsetWidth + 10;
var newHeight = myElement.offsetHeight + 10;
div1.style.width = newWidth + 'px';
myElement.style.height = newHeight + 'px'; // It will only be rearranged once
Copy the code

5. Bind events using event hosting

Binding events to DOM elements can affect page performance

  • On the one hand, the binding event itself consumes processing time
  • On the other hand, the browser saves event bindings, which also consume memory.

The more events bound to elements in a page, the more processing time and memory it takes, and the worse performance it will have

  • Therefore, the fewer events bound to the page, the better.

An elegant approach is to use event hosting, which uses event bubbling to bind event handling only to the parent element, handle events for all child elements, determine the source elements in the event handler based on the parameters passed in, and do different processing for different source elements.

  • This eliminates the need to bind events to each child element, reduces the number of event bindings managed, and improves natural performance.
  • This approach also provides great flexibility, allowing you to easily add or remove child elements without having to worry about changing the event binding if the element is removed or changed.

Example code is as follows:

// Get the parent node and add a click event
document.getElementById('list').addEventListener('click'.function(e) {
    // Check the event source element
    if (e.target && e.target.nodeName.toUpperCase === 'LI') {
        // Processing for child elements. }})Copy the code

In the above code, only the parent element is bound to the click event. When the child node is clicked, the click event will bubble, and the parent node will catch the event and check the source element through E.target and do the corresponding processing.

  • The event binding method has browser compatibility problems. You can use jQuery or wrap it yourself. Such as:
$('table').on('click'.'td'.function () {$(this).toggleClass('chosen')})Copy the code

Code word is not easy, praise encouragement!

Part reference “Web front-end development best Practice” party construction


Performance optimization set quick entry:

  • How to determine the best caching strategy for front-end resources?
    • Starting point for browser Cache- > cache-control
    • Browser caching mechanism (combined with response headers)
  • The relationship between <link> and <script> and DOM parsing rendering
    • Introduction to browser multi-process architecture
  • Understand Web performance concepts and common analysis tools
    • Using the Web performance analysis tools PageSpeed Insights and Lighthouse Tutorial
  • Web Performance – White screen time details and optimization
    • Web Performance -HTML and CSS optimization
    • Web Performance – Image optimization
    • Web Performance – Font optimization
    • Web Performance – JS optimization
    • Web Performance – Optimizing DOM operations (rearrange and redraw)
    • The basic principle of TCP transmission and optimization
    • Web Performance -CDN architecture introduction and optimization
      • Configure the CDN of the third-party library in the Webpack project and perform CDN fault tolerance
  • Front-end performance monitoring for real users