Why DOM is slow to operate.

Source: Internet
Author: User

Translated from: http://kb.cnblogs.com/page/534571/

Always heard Dom is very slow, to try to operate the DOM as little as possible, so I want to go further to explore why everyone will say so, in the online learning some information, this side of the collation.

First, the DOM object itself is also a JS object, so strictly speaking, not the operation of this object is slow, but that after manipulating the object, it will trigger some browser behavior, such as layout and drawing (paint). The following main introduction of these browser behavior, explain how a page is ultimately presented, in addition, from the point of view of the code to illustrate some bad practices and some optimization programs.

How the browser renders a page

A browser has many modules, which are responsible for rendering the page is the rendering engine module, more familiar with WebKit and gecko, etc., here will only involve the content of this module.

Use the text to outline the following process:

    • Parse the HTML and generate a DOM tree
    • Parse various styles and combine DOM tree to create a render tree
    • Calculates layout information for each node of the render tree, such as box position and size
    • Draw based on the render tree and take advantage of the browser's UI layer

Where the nodes on the DOM tree and the render tree are not one by one corresponding, such as a " display:none" node will only exist on the DOM tree, and will not appear on the render tree, because this node does not need to be drawn.

Is the basic process of webkit, in terms and gecko may be different, here paste Gecko flowchart, but the contents of the article will be unified use WebKit terminology.

There are many factors that affect page rendering, such as the location of link affecting the first screen rendering and so on. But here the main focus 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 a layout involves recalculation of the entire document layout.

But layout is definitely unavoidable, so we mostly want to minimize the number of layout.

What happens when the browser is layout

Before considering how to minimize the number of layout times, you need to know when the browser will be layout.

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

In general, the layout of the browser is lazy, that is to say: In the JS script execution, is not to update the DOM, any modifications to the DOM will be persisted in a queue, the current JS execution context after the completion of execution, will be based on the changes in the queue to do a layout.

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

The following actions will break the routine and trigger the browser to perform layout:

    • Get DOM properties to calculate with JS
    • Adding or removing DOM elements
    • Resize browser window size
    • Change font
    • CSS pseudo-class activation, such as: hover
    • Modify the DOM element style by JS and the style involves a change in size

Let's go through an example of intuitive feeling under:

Readvar H1 = element1.clientheight;//Write (invalidates layout) Element1.style.height = (H1 * 2) + ' px ';//Read (Trigge RS layout) var H2 = element2.clientheight;//Write (invalidates layout) Element2.style.height = (H2 * 2) + ' px ';//Read (Tri Ggers layout) var h3 = element3.clientheight;//Write (invalidates layout) Element3.style.height = (H3 * 2) + ' px ';  

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 is filtered to show layout only):

In the above example, the code first modifies the style of an element, and then reads the properties of another element clientHeight , because the previous modification causes the current DOM to be marked as dirty, in order to ensure that this property is accurately obtained, The browser will do a layout once (we find the developer tool of Chrome's conscience hints at our performance issue).

It is easy to optimize this code by pre-reading the required properties and modifying them together.

Readvar 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 bulk reads and writes mentioned above is a result of getting a property value that needs to be computed, so what are the values that need to be calculated?

In this link, you will be presented with most of the attributes you need to calculate: http://gent.ilcore.com/2011/03/how-not-to-trigger-layout-in-webkit.html

Take a look at other things:

Face a series of DOM operations

For a series of DOM operations (DOM element additions and deletions), 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);} List.appendchild (fragment);  

The core idea of this type of optimization is the same: a series of operations on a node that is not on the render tree, and then adding the node back to the render tree, so that no matter how complex the DOM operation, it will only trigger a layout.

Face changes in style

To change the style, we first need to know that not all changes to the style will trigger layout, because we know that layout is about calculating the size and size of the renderobject, so if I just change a color, it will not trigger layout.

Here is a Web site CSS triggers, detailing the effects of each CSS property on the browser's execution of layout and paint.

As in the following case, the optimization is the same as above, the attention of reading and writing.

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

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

function animate (from, to) {    if (from = = =) return  requestanimationframe (function () {from    + = 5    elemen T1.style.height = from + ' px '    animate (from, to)  

Each frame of the animation will cause layout, which is unavoidable, but in order to reduce the performance loss of the layout of the animation, you can absolutely position the animation elements, so that the animation elements out of the text flow, layout calculation will be much less.

Using Requestanimationframe

Any operations that could cause repainting should be put intorequestAnimationFrame

In real-world projects, code is divided into modules, which makes it difficult to organize bulk reads and writes as in the previous example. Then you can put the write operation in requestAnimationFrame the callback, unify the write operation before the next paint to execute.

Readvar H1 = element1.clientheight;//writerequestanimationframe (function () {    element1.style.height = (H1 * 2) + ' P x ';}); /Readvar H2 = element2.clientheight;//writerequestanimationframe (function () {    element2.style.height = (H2 * 2) + ' px ‘;});

The timing of the animation frame trigger is clearly observed, and the MDN is triggered before the paint, but I estimate that it is executed before the JS script gives control to the browser for the invalidated check of the DOM.

Other points of attention

In addition to the performance issues caused by triggering layout, here are some additional details:

The result of the cache selector, which reduces the DOM query. Special mention should be made here of htmlcollection. Htmlcollection is the document.getElementByTagName object type that is obtained, and the array type is similar but each time a property of this object is obtained, 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 handling htmlcollection objects.

In addition, reducing the nesting depth of DOM elements and optimizing the CSS, removing useless styles will help reduce the amount of layout calculation.

In DOM queries, querySelector and should be the querySelectorAll last choice, they are the most powerful, but the execution is very inefficient, if possible, try to substitute other methods.

Below are two links to jsperf that can compare performance.

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

2) http://jsperf.com/getelementbyid-vs-queryselector/218

My thoughts on the view layer

Above the content of the theoretical aspects of things, from a practical point of view, the above discussion is exactly what the view layer needs to deal with. There is 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, leads callback hell to, and predictably, imperative code like Fastdom lacks extensibility, and the key is that requestAnimationFrame it becomes an asynchronous programming problem. To let read and write state synchronization, it is necessary to write a wrapper on the basis of the DOM to internal control asynchronous read and write, but all to this, the feeling can be considered directly on the react ...

In short, try to avoid the above mentioned problems, but if you use a library, such as jquery, the layout of the problem is in the library itself abstraction. Like react introduced its own component model, using the virtual DOM to reduce DOM operations, and each time the state changes only once layout, I do not know if there is any use requestAnimationFrame of the inside, I feel to do a view layer is very difficult, Then prepare to learn react code. I hope that I will come back in a year or two to see this problem, there are 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

Why DOM is slow to operate.

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.