0%

DOM & BOM

This chapter introduces DOM concepts, the cost of manipulating the DOM, the mechanics of browser rendering engines, performance optimizations, and common interview questions such as throttling and anti-jitter.

DOM

1. What is the DOM

The DOM is the Document Object Model, Document Object Model, inside which are interfaces, i.e. methods and functions.

Official definition: DOM is a language-independent programmatic interface (API) for manipulating XML and HTML documents. It is mainly used in browsers to deal with HTML documents and is used to access data in the documents using the DOM API.
The DOM is a language-independent API, but its interface in the browser is implemented in JavaScript, and the DOM becomes an important part of the JS coding now.

2. JS modifying DOM elements is costly

Every manipulation of the DOM is preceded by access to the DOM, so it also consumes performance.
On top of this, because modifying the DOM causes the browser to recalculate the geometric changes to the page, triggers a rearrangement (reflow - rollback process) and redrawing of the browser’s templating engine, which in turn consumes even more performance.

3. How the browser rendering engine works and how it works

After the browser has downloaded all the resources in the page (e.g. HTML, JavaScript, CSS, images, etc.), a 6-step process occurs as follows.

  1. parse the HTML and build the DOM Tree (DOM Tree)

  2. parse the CSS to create the CSS rule tree (CSSOM Tree)

  3. merge the DOM Tree and CSS rule tree to produce the render tree (render Tree)

  4. layout the render tree, calculate the size and position of each element according to the generated render tree, and get the geometry information of each node. (Calculate the position and size of the elements based on the size of the viewport) (rearrangement will take this step)

  5. draw the render tree to draw the page pixel information (get the number of pixels per node based on the geometric information of each node on the render tree) (redrawing will take this step)

  6. the browser sends the pixel information for each layer of nodes to the GPU, which composites and draws the layers to display on the page

3.1 How does the browser rendering engine generate the render tree?

  1. traverses each visible node (except for tags such as meta, link, script, etc.; except for elements with display:none;) starting from the root of the DOM Tree
  2. for each visible node, find the corresponding rule in the CSSOM and apply the style rule to the corresponding node.
  3. for each visible node, and its corresponding style, combine to generate a render tree.

Not visible nodes: Nodes that will not render output (nodes that will not be displayed on the screen) are the following

  • tags such as meta, link, script, etc;
  • nodes that are hidden via css, i.e. display:none; (the opacity is not visible to humans, the computer can still see it, so it will still be rendered.) (So will elements with visibility as hidden be rendered? Do a test, a div set visibility invisible, left floating, surrounded by text, to see if the text around to let out a blank area. The final test proved that a blank space was indeed created, which means that the invisibility of visibility and opacity is only invisible to the human eye, but the computer will still calculate the position information and draw it out when generating the render tree. The result of the experiment is shown below :)

4. What is browser rendering engine reordering and redrawing?

4.1 Reordering

When a change in the DOM affects the geometric properties (width, height and position) of an element, the browser needs to recalculate the geometric properties of the element, and likewise the geometric properties and position of other adjacent elements will be affected as a result. The browser invalidates the affected part of the render tree and reconstructs the render tree. This process is called “reordering”.

4.2 Redrawing

Once the reordering is complete, the browser redraws the affected parts of the screen in a process called redrawing.
Since reordering is the step before redrawing, it is natural that reordering will result in redrawing when it occurs.

5. When is a reorder triggered?

Reordering is required when the page layout and geometry properties change.
(At its core: a reorder is triggered whenever an attribute causes a change in position information)

  1. a visible DOM element is added or removed. (A bunch of people queuing up, adding i.e. inserting a person in the middle/deleting i.e. a person in the middle going away, will inevitably affect the position information of the people in the back of the queue)

  2. element position change (reordering is because the position information has changed)

  3. element size change (outer margin, inner margin, border thickness, width, height, etc.)

  4. change in content, e.g. the amount/content of text changes, or an image is replaced by another image of a different size, font size changes, (bolded text?) Resulting in DOM element position, area change. [Calculations can consume CPU power] 5.

  5. page renderer initialization (this is a re-run of the process, right? Definitely a re-arrangement)

  6. Browser window size change (Position information will be forced to adjust and a re-arrangement will occur. See the gif below for a page where the position of a div element is not modified by viewport resizing, which also triggers a reorder) [consumes GPU computing power]. Experiment: resize viewport, where the position of a div element in a page is not modified by the viewport adjustment, also triggers a reorder

6. When is a repaint triggered?

  1. Relaying inevitably triggers redrawing, that’s for sure. This is because the browser’s workflow is to render after typesetting. Redraws flow back (roll back the process) to the typesetting stage, which requires the page to be redrawn afterwards.

  2. Cases in which redrawing is triggered individually.
    Situations other than when the size or position of an element changes, (e.g. when the font colour, background colour etc. changes). (I suspect that bold text will also trigger a redraw, but I have no evidence of this. In theory if you bold text inside a fixed size div, it should not affect the reordering of the elements that follow it, but it is possible that other adjacent text or elements inside that div will be reordered.)

7. Browser performance optimisation

7.1 Optimisation

Modern browsers are pretty well established, as multiple manipulations of the DOM can trigger reordering and redrawing and consume performance. So in addition to our conscious efforts to control the number of DOM manipulations, browsers have been designed to intelligently “throttle” DOM manipulations, for example by implementing queued changes and batch execution.

To explain, **browsers have a “queue” to store (save) js programs that need to manipulate the DOM. Whenever js code is executed to manipulate the dom, a program is first stored in this queue. After a certain period of time, the browser then links the “ES island” and “DOM island” (that is, the JS engine to link the rendering engine) in a centralised, bulk manner, thus triggering a DOM operation. **You can think of this as “one train after another”.

7.2 Users interrupting optimised actions

But we humans don’t perceive this, and may interrupt the browser’s “throttling” step by mistake. Forcing the browser to interrupt the current “wait” to perform an immediate dom operation. This allows the browser to hurry up and finish the JS manipulation of the DOM in its “queue” and then return the latest DOM position information to us. It’s like forcing the doors to close when you press the close button manually.

This happens when we get the DOM information.

Properties that interrupt browser optimisation and force a reorder to be triggered:

offsetTop, offsetLeft, offsetWidth, offsetHeight
scrollTop, scrollLeft, scrollWidth, scrollHeight
clientTop, clientLeft, clientWidth, clientHeight
getComputedStyle()

**Because it has to request the latest DOM information from the browser, the browser has to rush the JS engine to the rendering engine to perform a DOM operation. **

8. Why is manipulating the DOM very expensive?

  1. ES and DOM are two different things and each connection consumes performance
  2. manipulating the DOM leads to reordering and redrawing, which consumes CPU; redrawing consumes GPU

9. Anti-jitter & throttling — from SegmentFault-Ange

9.1 Explanation

Case in point: **Most websites will provide such a button: for returning to the top. **

This button will only appear after scrolling to a certain position from the top, so let’s now abstract this functional requirement - Listen to the browser scroll event and return the distance between the current scrollbar and the top. This could be implemented with a function.

However, a problem will be found when running it:** The default execution frequency of this function, too ! high! too! ** How high is it? In Chrome, for example, we can click to select the scrollbar of a page, then click once on the [down arrow key] of the keyboard, and find that the function executes 8-9 times!

However in reality we don’t need such high frequency feedback, after all the performance of the browser is limited and shouldn’t be wasted, so moving on to discuss how to optimise this scenario.

9.2 Anti-debounce

In short, debounce is the process of not executing immediately if a large number of the same events are triggered in a short period of time, but waiting a given amount of time before executing, and then retiming if the event is hit again within a given amount of time.

Based on the above scenario, the first idea is first proposed: Instead of executing the function immediately when the event is triggered for the first time, a deadline value of say 200ms is given and then.

  • If the scroll event is not triggered again within 200ms, then the function is executed
  • If the scroll event is triggered again within 200ms, then the current timing is cancelled and the timing starts again

Effect: if the same event is triggered in large numbers in a short period of time, the function will only be executed once.

9.3 Throttle

In short, a throttle is a function that is executed once at the same interval if a large number of the same events are triggered in a short period of time.

Continuing with this thought, the result of using the anti-throttling scheme above to deal with the problem is that

  • If a scroll event is constantly triggered for a limited period of time (e.g. some user is idle and holds down the scroll and keeps dragging it around), the current distance to the top will theoretically never be output as long as the triggering does not stop.

New requirement: What about giving feedback after a certain time interval even if the user keeps dragging the scroll bar?

It’s actually quite simple: we could design a function that similar to a control valve that opens periodically, i.e. let the function execute once and then temporarily deactivate for a certain period of time, and reactivate after that time (similar to a skill cooldown).

Effect: if the same event is triggered in large numbers over a short period of time, then after the function is executed once, the function does not work again for a specified period of time, and does not re-activate until after that time.