Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to do high-performance JavaScript DOM programming and rearrange and redraw

2025-02-14 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/02 Report--

This article introduces you how to carry out high-performance JavaScript DOM programming and rearrange and redraw, the content is very detailed, interested friends can refer to, hope to be helpful to you.

We know that DOM is an application program interface for manipulating XML and HTML documents, and it is expensive to use scripts for DOM operations. There is an apt analogy. Think of DOM and JavaScript (here ECMScript) as an island. They are connected by a toll bridge. Every time ECMAScript visits DOM, he has to go through this bridge and pay a "bridge toll." the more times he visits DOM, the higher the cost will be. Therefore, the recommended practice is to minimize the number of times to cross the bridge and try to stay on ECMAScript Island. It is impossible for us not to use the interface of DOM, so how can we improve the efficiency of the program?

1. DOM access and modification

Accessing the DOM element is costly ("bridge toll" you know), and modifying the element is even more expensive because it causes the browser to recalculate the geometric changes (rearranging and redrawing) of the page.

Of course, the worst-case scenario is to access or modify elements in a loop. Take a look at the following two pieces of code:

Var times = 15000

/ / code1

Console.time (1)

For (var I = 0; I < times; iTunes +) {

Document.getElementById ('myDiv1') [xss_clean] + =' a'

}

Console.timeEnd (1)

/ / code2

Console.time (2)

Var str =''

For (var I = 0; I < times; iTunes +) {

Str + ='a'

}

Document.getElementById ('myDiv2') [xss_clean] = str

Console.timeEnd (2)

As a result, the running time of * is a thousand times longer than that of the second time! (chrome version 44.0.2403.130m)

1: 2846.700ms

2: 1.046ms

The problem with the * snippet code is that the element is accessed twice for each iteration of the loop: once the value of the innerHTML is read and the other time it is rewritten, that is, each loop is crossing the bridge (rearrangement and redrawing will be explained in the next article)! The results fully show that the more times you visit the DOM, the slower the code runs. Therefore, the number of DOM visits can be reduced as much as possible, and stay on the ECMAScript side as far as possible.

2. HTML collection & traversing DOM

Another energy consumption point for operating DOM is traversing DOM. We usually collect a collection of HTML, such as getElementsByTagName (), document.links, etc., which I think everyone is familiar with. The result of the collection is an array-like collection that exists in a "real-time state" in real time, which means that when the underlying document object is updated, it is also updated automatically. What do you mean? It's very simple. Take a chestnut:

Apple

Orange

Banana

Var lis = document.getElementsByTagName ('li'); var peach = document.createElement (' li'); peach [XSS _ clean] = 'peach'; document.getElementById (' fruit') .appendChild (peach); console.log (lis.length); / / 4

And this is the source of inefficiency! Quite simply, just like array optimization, caching a length variable is ok (reading the length of a collection is much slower than reading the lengh of a normal array, because it is queried every time):

Console.time (0)

Var lis0 = document.getElementsByTagName ('li')

Var str0 =''

For (var I = 0; I < lis0.length; iTunes +) {

Str0 + = lis0 [I] [xss_clean]

}

Console.timeEnd (0)

Console.time (1)

Var lis1 = document.getElementsByTagName ('li')

Var str1 =''

For (var I = 0, len = lis1.length; I < len; iTunes +) {

Str1 + = lis1 [I] [xss_clean]

}

Console.timeEnd (1)

Let's see how much performance can be improved.

0: 0.974ms

1: 0.664ms

When the length of the collection is large (demo is 1000), the performance improvement is still significant.

"High performance JavaScript" proposes another optimization strategy, which points out that "because traversing an array is faster than traversing a collection, it is faster to access its properties if you copy the collection elements into the array first." after testing, it is not good to find this rule, so don't bother. The test code is as follows: (feel free to communicate with me if you have any doubts.)

Console.time (1)

Var lis1 = document.getElementsByTagName ('li')

Var str1 =''

For (var I = 0, len = lis1.length; I < len; iTunes +) {

Str1 + = lis1 [I] [xss_clean]

}

Console.timeEnd (1)

Console.time (2)

Var lis2 = document.getElementsByTagName ('li')

Var a = []

For (var I = 0, len = lis2.length; I < len; iTunes +)

A [I] = lis2 [I]

Var str2 =''

For (var I = 0, len = a. Duration; I < len; iTunes +) {

Str2 + = a [I] [xss_clean]

}

Console.timeEnd (2)

The * in this section introduces two native DOM methods, querySelector () and querySelectorAll (). The former returns an array (note that their return values do not change dynamically like the HTML collection), and the latter returns matching * * elements. Well, it doesn't always outperform the HTML collection traversal of the former.

Console.time (1)

Var lis1 = document.getElementsByTagName ('li')

Console.timeEnd (1)

Console.time (2)

Var lis2 = document.querySelectorAll ('li')

Console.timeEnd (2)

/ / 1: 0.038ms

/ / 2: 3.957ms

But because it is similar to CSS selection method, so in the combination selection, the efficiency will be improved, and convenient. For example, do a combined query like this:

Var elements = document.querySelectorAll ('# menu a')

Var elements = document.querySelectorAll ('div.warning, div.notice')

First review the previous high-performance JavaScript DOM programming, mainly mentioned two optimizations, one is to minimize the access to DOM, and put the operation on the ECMAScript side, and the other is to cache local variables as much as possible, such as length, etc. * introduced two new API querySelector () and querySelectorAll (), which can be boldly used when making combination choices. This article focuses on rearranging and redrawing where DOM programming may be the most time-consuming.

1. What is rearrangement and redrawing

After downloading all the components in the page-- HTML tags, JavaScript, CSS, and images-- the browser will parse and generate 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 node is displayed. Each node that needs to be displayed in the DOM tree has at least one corresponding node in the render tree (the hidden DOM element disply value is that none does not have a corresponding node in the render tree). The nodes in the render tree are called "frames" or "boxes", which conform to the definition of the CSS model, and understand that the page element is a box with padding, margins, borders, and positions. Once the DOM and render tree are built, the browser starts to display (draw) the page elements.

When the DOM changes affect the geometric attributes (width or height) of the element, the browser needs to recalculate the geometric attributes of the element, as well as the geometric attributes and positions of other elements. The browser invalidates the affected part of the render tree and reconstructs the render tree. This process is called rearrangement. After rearranging, the browser redraws the affected part to the screen, a process called redrawing. Due to the flow layout of the browser, the calculation of the render tree usually needs to be traversed only once. With the exception of table and its internal elements, it may require multiple calculations to determine the attributes of its nodes in the render tree, which usually takes three times as long as the equivalent elements. This is one reason why we should avoid using table for layout.

Not all DOM changes affect geometric attributes, such as changing the background color of an element does not affect the width and height of the element, in which case redrawing only occurs.

2. What is the cost of rearranging and redrawing?

How much does it cost to rearrange and redraw? Let's go back to the previous example of crossing the bridge, you may find that the time difference of a thousand times is not caused by "crossing the bridge". Every time "crossing the bridge" is actually accompanied by emphasis on arrangement and redrawing. and most of the energy consumption is here!

Var times = 15000

/ / every time code1 crosses the bridge + rearranges + redraws

Console.time (1)

For (var I = 0; I < times; iTunes +) {

Document.getElementById ('myDiv1') [xss_clean] + =' a'

}

Console.timeEnd (1)

/ / code2 only crosses the bridge

Console.time (2)

Var str =''

For (var I = 0; I < times; iTunes +) {

Var tmp = document.getElementById ('myDiv2') [xss_clean]

Str + ='a'

}

Document.getElementById ('myDiv2') [xss_clean] = str

Console.timeEnd (2)

/ / code3

Console.time (3)

Var _ str =''

For (var I = 0; I < times; iTunes +) {

_ str + ='a'

}

Document.getElementById ('myDiv3') [xss_clean] = _ str

Console.timeEnd (3)

/ / 1: 2874.619ms

/ / 2: 11.154ms

/ / 3: 1.282ms

The data doesn't lie, and you see, multiple visits to DOM are time-consuming for rearranging and redrawing.

3. When will the rearrangement occur

Obviously, every rearrangement will inevitably lead to repainting, so under what circumstances will the rearrangement occur?

Add or remove visible DOM elements

Element position change

Element size change

The content of the element changes (for example, one text is replaced by another picture of a different size)

Page rendering initialization (this cannot be avoided)

Browser window size change

All of this is obvious, and you may have had the experience of constantly changing the size of the browser window, resulting in the slow response of UI (even hanging up in some lower versions of IE). Now you may suddenly realize that, yes, it is caused by rearranging and redrawing again and again!

4. Queuing and refreshing of render tree changes

Consider the following code:

Var ele = document.getElementById ('myDiv')

Ele.style.borderLeft = '1px'

Ele.style.borderRight = '2px'

Ele.style.padding = '5px'

At first glance, the style of the element has changed three times, and each change will lead to rearrangement and redrawing, so there are a total of three rearrangements and redrawing processes, but the browser is not so stupid. It will "save" three changes (most browsers optimize the rearrangement process by queuing changes and batch execution), one at a time! However, there are times when you may (often unwittingly) force a refresh of the queue and require scheduled tasks to be executed immediately. The operation of getting layout information can cause the queue to refresh, such as:

OffsetTop, offsetLeft, offsetWidth, offsetHeight

ScrollTop, scrollLeft, scrollWidth, scrollHeight

ClientTop, clientLeft, clientWidth, clientHeight

GetComputedStyle () (currentStyle in IE)

Modify the above code slightly:

Var ele = document.getElementById ('myDiv')

Ele.style.borderLeft = '1px'

Ele.style.borderRight = '2px'

/ / here use offsetHeight

/ /...

Ele.style.padding = '5px'

Because the offsetHeight property needs to return the layout information of * *, the browser has to perform the "pending change" in the rendering queue and trigger a rearrangement to return the correct value (even if the changed style attribute in the queue has nothing to do with the property value you want to get), so the above code, the first two operations will be cached in the rendering queue to be processed, but once the offsetHeight attribute is requested The queue is executed immediately, so there are a total of two rearrangements and redrawings. So try not to query when the layout information changes.

5. Minimize rearrangement and redrawing

Let's take a look at the code above:

Var ele = document.getElementById ('myDiv')

Ele.style.borderLeft = '1px'

Ele.style.borderRight = '2px'

Ele.style.padding = '5px'

Each of the three style attributes will affect the geometry of the element. Although most modern browsers are optimized to cause only one rearrangement, as above, if a timely attribute is requested, the queue will be forced to refresh, and this code accesses the DOM four times, and an obvious optimization strategy is to synthesize their operations once, so that the DOM will be modified only once:

Var ele = document.getElementById ('myDiv')

/ / 1. Rewrite style

Ele.style.cssText = 'border-left: 1px; border-right: 2px; padding: 5pxscape'

/ / 2. Add style

Ele.style.cssText + = 'border-;eft: 1pxscape'

/ / 3. Use class

Ele.className = 'active'

6. Application of fragment element

Consider a question by looking at the following code:

Apple

Orange

If you want to add peach and watermelon options to your code, what will you do?

Var lis = document.getElementById ('fruit')

Var li = document.createElement ('li')

Li [XSS _ clean] = 'apple'

Lis.appendChild (li)

Var li = document.createElement ('li')

Li [XSS _ clean] = 'watermelon'

Lis.appendChild (li)

It's easy to think of the above code, but obviously, it has been rearranged twice, how to break it? As we said earlier, the hidden element is not in the render tree, which is great. We can first hide (display=none) the ul element whose id is fruit, then add the li element, and then display it, but it may flash in the actual operation, and the reason is easy to understand. At this point, the fragment element has the opportunity to display its talents.

Var fragment = document.createDocumentFragment ()

Var li = document.createElement ('li')

Li [XSS _ clean] = 'apple'

Fragment.appendChild (li)

Var li = document.createElement ('li')

Li [XSS _ clean] = 'watermelon'

Fragment.appendChild (li)

Document.getElementById ('fruit') .appendChild (fragment)

The document fragment is a lightweight document object that is designed to accomplish this kind of task-- updating and moving nodes. A convenient grammatical feature of a document fragment is that when you attach a fragment to a node, it is actually a child node of the fragment, not the fragment itself. Only one rearrangement was triggered and only one real-time DOM was accessed.

7. Detach the element from the animation stream

It is a common interaction mode to show and hide some pages by expanding / collapsing. It usually includes geometric animation of the expanded area and pushes the rest of the page down.

In general, rearrangement affects only a small portion of the render tree, but it may also affect a large portion, or even the entire render tree. The fewer times the browser needs to be rearranged, the faster the application responds. So when an animation at the top of the page moves over the rest of the page, it leads to an expensive large-scale rearrangement that makes the page feel like a meal. The more nodes in the render tree that need to be recalculated, the worse the situation will be.

Use the following steps to avoid most of the rearrangements on the page:

Use absolute position to locate animation elements on the page and detach them from the document stream

Get the element moving. When it expands, it temporarily overwrites part of the page. But this is only a small area of the page redrawing process, will not produce rearrangement and redraw most of the content of the page.

Restore positioning when the animation is over, so that other elements of the document are moved down only once

8. Summary

Rearrangement and redrawing is one of the main reasons for energy consumption in DOM programming. When it comes to DOM programming, you can refer to the following points:

Try not to query when the layout information changes (it will cause the rendering queue to be forced to refresh)

Multiple attribute changes to the same DOM can be written together (reduce DOM access and reduce the risk of forcing rendering queue refresh to 0)

If you want to add DOM in batch, you can first detach the element from the document stream, and then bring it into the document stream after the operation. This will only trigger a rearrangement (the application of fragment elements).

Set the position attribute to absolute or fixed for elements that need to be rearranged multiple times, so that this element is detached from the document stream and its changes do not affect other elements. For example, animated elements are set to absolute positioning.

On how to carry out high-performance JavaScript DOM programming and rearrangement and redrawing to share here, I hope the above content can be of some help to you, can learn more knowledge. If you think the article is good, you can share it for more people to see.

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report