Why is DOM so slow to operate,

Source: Internet
Author: User
Tags chrome developer

Always heard that the DOM is very slow, to minimize the operation of the DOM, so I would like to further explore why everyone would say so, on the internet to learn some information, this is sorted out.

First of all, the DOM object itself is also a JS object, so strictly speaking, is not to manipulate the object slow, but that the operation of the object, will trigger some browser behavior, such as layout (layout) and drawing (paint). The following main introduction of these browser behavior, explain how a page is eventually presented, and also from the point of view of the code, to explain some bad practices and some optimization programs. how the browser renders a single page

A browser has many modules, which is responsible for rendering the page is the rendering engine module, more familiar with the WebKit and Gecko, and here will only involve the content of this module.
The process is outlined in words: parsing HTML, and generating a DOM tree parsing various styles and combining DOM tree to generate a render trees to compute layout information for each node of render, such as box position and size according to render Tree and draw using the UI layer of the browser

The nodes on DOM tree and render are not one by one corresponding, for example, a "display:none" node will only exist on DOM tree, not on the render tree, because the node does not need to be drawn.

The above diagram is the basic flow of webkit, in terms and gecko may be different, here to paste the Gecko flowchart, but the article below will unify the use of WebKit terminology.

There are many factors affecting page rendering, such as the location of link will affect the first screen rendering. But the main focus here is on layout-related content.

Paint is a time-consuming process, but layout is a much more time-consuming process, and we cannot be sure that layout must be Top-down or bottom-up, and that even one layout will involve a recalculation of the entire document layout.

But layout is certainly unavoidable, so we are mainly to minimize the number of layout. under what circumstances will the browser be layout

Before considering how to minimize the number of layout, understand when the browser will be layout.

Layout (reflow) is generally referred to as a layout, which is used to calculate the position and size of elements in a document, and is an important step before rendering. In the first time when the HTML is loaded, there will be a layout, JS script execution and style changes will also cause the browser to perform layout, which is the main content of this article to discuss.

Under normal circumstances, browser layout is lazy, that is to say: In the JS script execution, is not to update the DOM, any changes to the DOM will be held in a queue, in the current JS execution context completed, will be based on the changes in the queue, a layout.

However, sometimes you want to get the latest DOM node information in the JS code immediately, the browser has to execute layout in advance, which is the main cause of DOM performance problems.

If the following operation will break the routine, and trigger the browser to perform layout through JS to get the DOM properties to be computed add or remove DOM elements resize browser window size change font CSS Pseudo class activation, such as: hover through JS modify DOM element style and the style involves the change of size

Let's use an example to intuitively feel the following:

Read
var h1 = element1.clientheight;

Write (invalidates layout)
Element1.style.height = (H1 * 2) + ' px ';

Read (triggers layout)
var h2 = element2.clientheight;

Write (invalidates layout)
Element2.style.height = (H2 * 2) + ' px ';

Read (triggers layout)
var h3 = Element3.clientheight;

Write (Invalidates layout)

ClientHeight, this property needs to be computed, so it triggers a layout of the browser. Let's take a look at the Chrome (v47.0) developer tool (the timeline record in the screenshot has been filtered to show only layout):

In the example above, the code first modifies the style of an element, then reads the ClientHeight property of another element, and as a result of previous modifications, the current DOM is marked as dirty, in order to ensure that the property is accurately retrieved, The browser makes a layout (we find that the Chrome developer tool has a conscience that prompts us for this performance problem).

The optimization of this code is simple, read the desired attributes, and modify them together.

Read
var h1 = element1.clientheight;  
var h2 = Element2.clientheight;  
var h3 = Element3.clientheight;

Write (invalidates layout)
Element1.style.height = (H1 * 2) + ' px ';  
Element2.style.height = (H2 * 2) + ' px ';  

Take a look at this situation:

Here are some other optimization scenarios. solutions to minimize layout

One of the above mentioned bulk reads and writes is one, mainly because of getting a property value that needs to be computed, and which values need to be computed.

This link contains a description of most of the properties to be computed: http://gent.ilcore.com/2011/03/how-not-to-trigger-layout-in-webkit.html

Let's look at something else: the face of a series of DOM operations

For a series of DOM operations (additions and deletions of DOM elements), you can have the following scenarios:
-DocumentFragment
-Display:none
-CloneNode
For example (in the case of DocumentFragment only):

var fragment = Document.createdocumentfragment ();  
for (Var i=0 i < items.length; i++) {  
  var item = document.createelement ("li");
  Item.appendchild (document.createTextNode ("option" + i);
  Fragment.appendchild (item);
}

The core idea of such an optimization scheme is the same, that is, to start a series of operations on a node that is not on the render tree, and then add the node back to render tree, so that no matter how complex the DOM operation, the end will only trigger a layout. face the change of style

For style changes, we first need to know that not all style changes will trigger layout, because we know that layout's job is to compute renderobject size and size information, so if I just change one color, it won't trigger layout.

Here is a Web site CSS triggers, detailing the effects of individual CSS properties on browser execution layout and paint.

As in the case below, the optimization is the same as the above, note that reading and writing can be.

Elem.style.height = "100px"; Mark invalidated  
elem.style.width = "100px";  
Elem.style.marginRight = "10px";

But to mention the animation, this side is about JS animation, such as:

Function animate {  
  if (from = = to) return

  requestanimationframe (function () {from
    + = 5
    elemen T1.style.height = from + "px"
    animate (from)
  })
}

Each frame of the animation will cause layout, which is unavoidable, but in order to reduce the layout performance loss of the animation, the animation elements can be absolutely positioned so that the animation elements out of the text stream, the layout calculation will be much reduced. using Requestanimationframe

Any action that might cause a redraw should be placed in the Requestanimationframe

In real-world projects, code is divided into modules, and it is difficult to organize bulk reads and writes like the example above. Then you can put the write operation in the Requestanimationframe callback, unified let write operation before the next paint execution.

Read
var h1 = element1.clientheight;

Write
requestanimationframe (function () {  
  element1.style.height = (H1 * 2) + ' px ';
});

Read
var h2 = element2.clientheight;

Write
requestanimationframe (function () {  
  element2.style.height = (H2 * 2) + ' px ';
});


The timing of the animation frame trigger can be clearly observed, MDN said to be triggered before paint, but I estimate it is performed before the JS script gives control to the browser for a invalidated check of DOM. other points of attention

In addition to the performance problems caused by triggering layout, here are some other details:

The result of the cache selector, which reduces the DOM query. Special mention should be made of htmlcollection here. Htmlcollection is the type of object that is obtained by document.getelementbytagname, and the array type is similar, but each time a property of the object is fetched, it is equivalent to a DOM query:

var divs = document.getelementsbytagname ("div");  
for (var i = 0; i < divs.length i++) {  //infinite loop  
  document.body.appendChild (document.createelement ("div "));
}

For example, the above code will cause an infinite loop, so do some caching when dealing with Htmlcollection objects.

In addition, reducing the nesting depth of DOM elements and optimizing CSS, eliminating unwanted styles can help reduce the amount of layout computing.

In DOM queries, Queryselector and Queryselectorall should be the last choice, they are the most powerful, but inefficient and, if possible, replaced with other methods.

Below are two jsperf links to compare performance.

1) https://jsperf.com/getelementsbyclassname-vs-queryselectorall/162

2 http://jsperf.com/getelementbyid-vs-queryselector/218 own ideas about the view layer

The content of the above theoretical aspects of the more, from a practical point of view, the above discussion is exactly what the view layer needs to deal with. There's already a library fastdom to do this, but its code is this:

Fastdom.read (function () {  
  console.log (' read ');
});

Fastdom.write (function () {  
  console.log (' write ');
});

The problem is obvious, it leads to callback hell, and it can also be foreseen that imperative code like Fastdom has a lack of extensibility, and the key is that requestanimationframe becomes the problem of asynchronous programming. To allow read and write state synchronization, it is necessary to write a wrapper on the basis of DOM to internal control of asynchronous reading and writing, but to this, the feeling can be considered directly on the react ...

In short, try to avoid the problems mentioned above, but if you use libraries, such as jquery, the layout problem is in the abstract of the library itself. Like react introduces its own component model, uses the virtual DOM to reduce DOM operations, and can be changed every time the state only once layout, I do not know if the internal use of requestanimationframe and so on, It's difficult to feel like you need to do a view layer, and then get ready to learn the react code. I hope that when I come to see this problem in a year or two, I can have some new ideas. Reference http://www.html5rocks.com/en/tutorials/internals/howbrowserswork/https://dev.opera.com/ Articles/efficient-javascript/?page=3 http://wilsonpage.co.uk/preventing-layout-thrashing/https:// www.nczonline.net/blog/2009/02/03/speed-up-your-javascript-part-4/http://gent.ilcore.com/2011/03/ how-not-to-trigger-layout-in-webkit.html

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.