In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-02-25 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/02 Report--
This article mainly explains why the DOM operation in JavaScript is so slow. Interested friends may wish to have a look at it. The method introduced in this paper is simple, fast and practical. Let's let the editor take you to learn why the DOM operation in JavaScript is so slow.
How browsers render a page
A browser has many modules, of which the rendering engine module is responsible for rendering the page, and the familiar ones are WebKit and Gecko, and only this module will be covered here.
Let's first outline the process in words:
Parse HTML and generate a DOM tree
Parse various styles and combine DOM tree to generate a Render tree
Calculate layout information for each node of the Render tree, such as the location and size of the box
Draw according to Render tree and use the UI layer of the browser
The nodes on DOM tree and Render tree do not correspond one to one. For example, a node of "display:none" will only exist on DOM tree, not on Render tree, because this node does not need to be drawn.
The above figure is the basic process of Webkit, and the terminology may be different from that of Gecko. The flow chart of Gecko is posted here, but the terminology of Webkit is used uniformly at the bottom of the article.
There are many factors that affect the page rendering, such as the location of the link will affect the first screen presentation and so on. But here we mainly focus on the content related to layout.
Paint is a time-consuming process, but layout is a more time-consuming process, we are not sure that layout must be top-down or bottom-up, or even a layout will involve a recalculation of the entire document layout.
But layout is certainly inevitable, so the main thing we need to do is to minimize the number of layout.
Under what circumstances will the browser perform layout?
Before you think about how to minimize the number of layout, you need to know when the browser will do layout.
Layout (reflow) is commonly referred to as layout, and this operation is used to calculate the location and size of elements in a document, which is an important step before rendering. When HTML*** is loaded, there will be a time in addition to layout, the execution of js scripts and style changes will also cause browsers to execute layout, which is the main content of this article.
In general, the layout of the browser is lazy, that is to say, when the js script is executed, the DOM will not be updated, and any changes to the DOM will be temporarily stored in a queue. After the execution context of the current js is completed, a layout will be made according to the changes in this queue.
However, sometimes browsers have to execute layout in advance if they want to get the DOM node information of * * immediately in the js code, which is the main cause of DOM performance problems.
The following actions break the rules and trigger the browser to execute layout:
Get the DOM attribute that needs to be calculated through js
Add or remove DOM elements
Resize browser window size
Change the font
Activation of css pseudo-classes, such as hover
Modify the DOM element style through js and the style involves size change
Let's get an intuitive feeling through an example:
/ / Read var H2 = element1.clientHeight; / / Write (invalidates layout) element1.style.height = (H2 * 2) + 'px'; / / Read (triggers layout) var h3 = element2.clientHeight; / / Write (invalidates layout) element2.style.height = (h3 * 2) +' px'; / / Read (triggers layout) var h4 = element3.clientHeight; / / Write (invalidates layout) element3.style.height = (h4 * 2) + 'px'
ClientHeight, this property needs to be calculated, so a layout of the browser is triggered. Let's take a look at the developer tool of chrome (v47.0) (the timeline record in the screenshot has been filtered to show only layout):
In the above example, the code first modifies the style of one element, and then reads the clientHeight attribute of another element. Due to the previous modification, the current DOM is marked as dirty. In order to ensure that this attribute can be accurately obtained, the browser will do a layout (we found that the developer's tool conscience of chrome alerted us to this performance problem).
Optimizing this code is simple, read the required properties in advance and modify them together.
/ / Read var H2 = element1.clientHeight; var h3 = element2.clientHeight; var h4 = element3.clientHeight; / / Write (invalidates layout) element1.style.height = (H2 * 2) + 'px'; element2.style.height = (h3 * 2) +' px'; element3.style.height = (h4 * 2) + 'px'
Let's take a look at this time:
Here are some other optimization schemes.
A scheme for minimizing layout
One of the batch reads and writes mentioned above is one, mainly due to obtaining a property value that needs to be calculated, so which values need to be calculated?
This link describes most of the properties that need to be calculated: http://gent.ilcore.com/2011/03/how-not-to-trigger-layout-in-webkit.html
Let's take a look at something else:
Facing a series of DOM operations
For a series of DOM operations (additions, deletions and modifications of DOM elements), you can have the following solution:
DocumentFragment
Display: none
CloneNode
For example (just take documentFragment as an example):
Var fragment = document.createDocumentFragment (); for (var iTuno; I < items.length; iTunes +) {var item = document.createElement ("li"); item.appendChild (document.createTextNode ("Option" + I); fragment.appendChild (item);} list.appendChild (fragment)
The core idea of this kind of optimization scheme is the same, that is, first perform a series of operations on a node that is not on the Render tree, and then add the node back to the Render tree, so that no matter how complex the DOM operation is, the layout will only be triggered once.
Face the modification of the 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 calculate the size and size information of RenderObject, so if I just change a color, I will not trigger layout.
Here is a website, CSS triggers, that details the impact of various CSS properties on browser execution of layout and paint.
In the case of the following, which is the same as the optimization mentioned above, just pay attention to reading and writing.
Elem.style.height = "100px"; / / mark invalidated elem.style.width = "100px"; elem.style.marginRight = "10px"; elem.clientHeight / / force layout here
But to mention animation, we are talking about js animation here, such as:
Function animate (from, to) {if (from = to) return requestAnimationFrame (function () {from + = 5 element1.style.height = from + "px" animate (from, to)})} animate (100500)
Every frame of the animation will lead to layout, which is inevitable, but in order to reduce the performance loss of layout caused by animation, we can position the animation elements absolutely, so that the animation elements are separated from the text stream, and the amount of calculation of layout will be greatly reduced.
Use requestAnimationFrame
Any operation that may lead to redrawing should be placed in the requestAnimationFrame
In a real project, the code is divided into modules, so it is difficult to organize batch reads and writes as in the example above. At this point, you can put the write operation in the callback of requestAnimationFrame and let the write operation be performed before the next paint.
/ / Read var H2 = element1.clientHeight; / / Write requestAnimationFrame (function () {element1.style.height = (H2 * 2) + 'px';}); / / Read var h3 = element2.clientHeight; / / Write requestAnimationFrame (function () {element2.style.height = (h3 * 2) +' px';}))
The timing of the Animation Frame trigger can be clearly observed, which is said on MDN to be triggered before the paint, but I estimate it is executed before the js script gives control to the browser to invalidated check for DOM.
Other points of attention
In addition to the performance problems caused by triggering layout, here are some other details:
Cache the results of the selector to reduce DOM queries. Here I would like to mention HTMLCollection in particular. HTMLCollection is an object type obtained through document.getElementByTagName, similar to an array type, but each time you get a property of this object, it is equivalent to a DOM query:
Var divs = document.getElementsByTagName ("div"); for (var I = 0; I < divs.length; iTunes +) {/ / infinite loop document.body.appendChild (document.createElement ("div"));}
For example, the above code will cause a * * loop, so you need to do some caching when dealing with HTMLCollection objects.
In addition, reducing the nesting depth of DOM elements and optimizing css, and removing useless styles are helpful to reduce the computational complexity of layout.
When querying DOM, querySelector and querySelectorAll should be the choice of * *. They have a large function, but the execution efficiency is very poor. If possible, try to replace them with other methods.
My own thoughts on the View layer
There is a lot of theoretical content above, and from a practical point of view, what is discussed above is exactly what the View layer needs to deal with. There is already a library FastDOM to do this, but the code looks like this:
Fastdom.read (function () {console.log ('read');}); fastdom.write (function () {console.log (' write');})
The problem is obvious, can lead to callback hell, and can also foresee the lack of extensibility of imperative code like FastDOM, the key is that after using requestAnimationFrame, it becomes an asynchronous programming problem. To synchronize the state of reading and writing, it is necessary to write a Wrapper on the basis of DOM to internally control asynchronous reading and writing, but at this point, it feels like you can consider going directly to React.
At this point, I believe you have a deeper understanding of "why the DOM operation in JavaScript is so slow". You might as well do it in practice. Here is the website, more related content can enter the relevant channels to inquire, follow us, continue to learn!
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.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.