Moment For Technology

Browser event loops and rendering

Posted on Nov. 27, 2023, 1:55 p.m. by 蕭宗翰
Category: The front end Tag: The front end The browser


Recently, I wanted to learn more about browser rendering, so I went to read the relevant documentation. Because it involves the cycle of events, I wrote it along with you, and here I share my understanding with you. Because the blogger is just new, English reading level is limited, if there are mistakes, please correct them.

Event loop

It's worth noting that many people refer to event loops as javascript event loops, but event loops are not provided by javascript Engines such as V8, but by runtime, such as browsers and Node.js. The whole loop is quite complicated, and there are only some important points for the service center.


Event loops: In order to coordinate events, user interactions, scripting, rendering, networking, and so on, user agents must use event loops. Each agent has an associated event loop that is unique to the agent.

Task Queue (s) : A task queue, which may have one or more tasks (usually called macro tasks).

Note: Queues are actually sets, not queues, because step 1 of the event loop processing model is to grab the first runnable queue from the selected queue, not necessarily the first queue, but queues' tasks are executed sequentially.

Microtask Queue: A microtask queue that is initially empty. Microtasks created by task are pushed into it.

Rendering Opportunity: A variable to determine whether or not to render. It takes into account hardware refresh rate limits, whether user agent pages are visible for performance reasons, and so on. Render opportunities should occur regularly. (I.e., each render interval should be roughly the same, e.g. 16.6ms or 33.3ms, instead of losing frames, e.g. 16.6ms multiple times and suddenly 33.3ms)


  • Task queue(s) is a task queue that has tasks that can be executed. If there is a task queue, execute the tasks in it. If there is no task queue, skip this step and execute the microTask queue.

  • It then checks to see if the MicroTask queue is empty, executes if it is not, and executes if a new MicroTask is created along the way.

  • Update the value now to current High resolution time. (Guess updated return value of here)

  • Set rendering opportunity according to the description in the definition

  • If rendering opportunity exists is true and at least one of the following conditions is true. If the callbacks are not empty (which can be added using requestAnimationFrame), do the following steps, otherwise skip this step

    • If the size of the window changes, the listener is executedresizeMethods.
    • If the page scrolls, executescrollMethods.
    • performrequestAnimationFrameThe callback is passed innowAs a timestamp.
    • performIntersectionObserverThe callback is passed innowAs a timestamp.
    • Rerender the user interface.
  • Determines whether to call the requestIdleCallback callback, which is usually called when the browser is idle.

Task source and Microtask source

  • The Task source

    • The entire JS file can be seen as the first macro task.
    • DOM manipulation
    • User interaction, such as keyboard or mouse input.
    • Network task
    • History traversal, such as calling history.back() and similar apis.
  • Microtask source

    • process.nextTick
    • Promise
    • Async/Await
    • MutationObserver

Browser rendering

If the above decision is indeed to render, then let's describe the render steps.

General steps

  • Generic DOM Tree Generates DOM trees

    • Generate a DOM tree through lexical analysis and grammar analysis.
    • HTML grammar is different from most of the programming language, it is not a type ii grammar (context-free grammar), but the type of grammar (context), because in the production of centre-left need not be a single non-terminal, such as two nested Form when parsing out only one layer, indicating a production related to the Form, It has at least two symbols on the left, which is relevant to the previous state, which is context.
  • Calculate style calculates the style

    • Formatting: These text browsers don't understand, so generate an object with various CSS styles that is viewed through Document.stylesheets.

    • Standardization: convert REM, EM,vw, etc to PX and color to # XXXXXX, etc

    • Inheritance and overlap: Finally, the final style attributes are calculated by inheritance and overlap. Inheritance is a subset of attributes that may be inherited from a parent element and applied to itself

      • Start by finding all the rules that an element can match

      • Sort by explicit weight and source

        From most to least: readers'! Impotant statement author's! Important declaration General declaration for author General declaration for reader default style declaration for user agent

      • According to the order of special index, special index shape such as 0, 0, 0, 0, from the beginning of the high, meet different larger winner

        Row 1 0 0 0 id selector each 0 1 0 0 class selector, attribute selector, pseudo-class selector each 0 0 1 0 0 element selector, pseudo-element selector each 0 0 0 1 * is 0 0 0 0 0 0 0 0 inherits is no specific index

      • If that's not clear, the statement that comes later wins

  • Update Layout Tree Updates the layout tree

    • Iterate over the generated DOM tree nodes and add them to the layout tree.
    • Computes the coordinate positions of nodes in the layout tree.
  • Updata Layer tree Updates the layer tree

    Yes, we can't render with position, style, and DOM because we don't know the order between layers, so we have to build the layer tree

  • Paint draw

This step is to draw the pixel information of the page

  • Composite layers

    Combine the layers

  • Rasterize paint Rasterize graphics

    Rasterize the above data into bitmaps using a rasterized thread pool

  • The display shows

    Bitmap data information to the graphics card, display to the display

Reflow and repaint

So when we change the style, the images will change, but do they actually go through the above flow?

Reflow (rearrangement)

When the size, structure, or attributes of some or all of the elements in the DOM tree change, the process by which the browser rerenders some or all of the document is called backflow.

Operations that cause backflow:

  • Page first render
  • The browser window size changed. Procedure
  • The size or position of the element changed
  • Element content changes (number of words or image size, etc.)
  • Element font size changes
  • Add or remove visibleDOMThe element
  • The activationCSSPseudo classes (e.g.:hover)
  • Query some properties or call some methods

Some common properties and methods that cause backflow:

  • Client:clientWidth,clientHeight,clientTop,clientLeft
  • The family of offset:offsetWidth,offsetHeight,offsetTop,offsetLeft
  • Scroll the family:scrollWidth,scrollHeight,scrollTop,scrollLeft
  • scrollIntoView(),scrollIntoViewIfNeeded()
  • getComputedStyle()
  • getBoundingClientRect()
  • scrollTo()

Repaint redraw

When a change in the style of an element in a page does not affect its position in the document flow (e.g., color, background-color, visibility, etc.), the browser assigns the new style to the element and redraws it, a process called redraw.

To compare

The cost of reflow is higher than that of Repaint, because reflow obviously does all of the above steps, and repaint skips the update Layout tree step because the position has not changed, so if reflow is required, Throttling operations should be carried out if necessary.

function throttle(func, wait) {
    let previous = 0;
    return function () {
        const now =;
        const context = this;
        const args = arguments;
        if(now - previous  wait) { func.apply(context, args); previous = now; }}}Copy the code

Now let's simply create a moving image to see if it's the same as above

Performance, shown above, moves through marginstyle
    #move {
        width: 20px;
        height: 20px;
        background-color: aqua;
div id="move"/div
    let move = document.querySelector("#move");
    let i = 0;
    setInterval(() =  {['margin-top'] = i++ * 0.1 + 'px';
    }, 10)
/scriptMove through Tranform, as shown below by Performancestyle
    #move {
        width: 20px;
        height: 20px;
        background-color: aqua;
div id="move"/div
    let move = document.querySelector("#move");
    let i = 0;
    setInterval(() =  {['transform'] = `translateY(${i++*0.1}px)`;
    }, 1)
Copy the code

You can see that Repaint does not carry out the layout process.

How to avoid


  • Avoid the use oftableLayout.
  • As far as possible inDOMThe end of the tree changesclass.
  • Avoid setting multiple inline styles.
  • Apply the animation effect topositionProperties forabsoluteorfixedOn the element of.
  • Avoid the use ofCSSExpressions (e.g.calc()).


  • Avoid frequent manipulation of styles; it is best to rewrite them all at oncestyleProperty, or define the style list asclassAnd change it onceclassProperties.
  • Avoid frequent operationsDOM, create adocumentFragmentApply all of them to itDOM manipulation, and finally add it to the document.
  • You can also set the element firstdisplay: none, and then display it after the operation. Because in thedisplayProperties fornoneOn the element ofDOMThe operation does not cause backflow and redraw.
  • Avoid frequently reading properties that cause backflow/redraw, and if you do need to use them more than once, cache them in a variable.
  • Use absolute positioning on elements with complex animations to keep them out of the document stream, which would otherwise cause frequent backflow of parent elements and subsequent elements.


Refer to the event loop for specific call timing.


Tell the browser window. RequestAnimationFrame () - you want to perform an animation, and required the browser until the next redraw calls the specified callback function to update the animation. This method takes as an argument a callback function that is executed before the browser's next redraw.

In fact, although it is named with animation, it does not necessarily perform animation-related operations. We can also use it for throttling, so that its callback function ensures that it only performs once per frame at most.

function throttle(func, wait) {
    let flag = false;
    return function() {
        if (flag) return;
        flag = true;
        const context = this;
        const args = arguments;
        requestAnimationFrame(() =  {
            flag = false; func.apply(context, args); }}})Copy the code


Window. RequestIdleCallback () method inserts a function, this function will be called the browser idle period. This enables developers to perform background and low-priority work on the main event loop without affecting the delay of critical events such as animations and input responses. Functions are typically executed in first-come-first-called order; however, if a callback function specifies a timeout, it is possible to scramble the order of execution in order to execute the function before it times out.


The HTML Standard ( :

About (Moment For Technology) is a global community with thousands techies from across the global hang out!Passionate technologists, be it gadget freaks, tech enthusiasts, coders, technopreneurs, or CIOs, you would find them all here.