This is the second day of my participation in the November Gwen Challenge. Check out the details: the last Gwen Challenge 2021

It starts with the user entering the URL in the browser

Interviewers often ask: What happens from the user entering the URL in the browser to the final rendering of the page?

The answers are as follows:

  1. The user enters the URL address
  2. The browser parses the URL to resolve the host name
  3. The browser converts the host name to the server IP address. (The browser first looks up the local DNS cache list and then sends a query request to the browser’s default DNS server.)
  4. The browser interprets the port number from the URL
  5. The browser establishes a TCP connection to the target Web server (three-way handshake)
  6. The browser sends an HTTP request packet to the server
  7. The server returns an HTTP response packet to the browser
  8. Close the connection browser to parse the document
  9. If there are resources in the document, repeat actions 6, 7, 8 until all resources are loaded

The browser

There are five major browsers in use: Internet Explorer, Firefox, Safari, Chrome and Opera. This article uses open source browsers, namely Firefox, Chrome, and Safari (partially open source). According to StatCounter browser statistics, Firefox, Safari, and Chrome currently (as of November 2021) share 87.39% of the total market. As you can see, open source browsers are now a very solid part of the browser market.

The main role of the browser

The main function of the browser is to make a request to the server to display the network resource of your choice in the browser window. These network resources include the following:

  • HTML
  • CSS
  • JavaScript
  • Media (pictures, videos, etc.)

It can also be divided into HTML documents (HTML/CSS/JS), PDF, images, videos, and other types.

How browsers interpret and display HTML files is specified in the HTML and CSS specifications. These specifications are maintained by the Web standardization group W3C (World Wide Web Consortium). For years, browsers failed to fully comply with these specifications while developing their own extensions, which created serious compatibility problems for web developers. Today, most browsers are more or less compliant.

The browser user interface has many elements in common with each other, including:

  • The address bar used to enter the URI
  • Forward and back buttons
  • Bookmark Settings options
  • Refresh and stop buttons that refresh and stop loading the current document
  • The home button to return to the home page

The structure of the browser

  1. User Interface – includes address bar, forward/back buttons, bookmark menu, etc. All parts of the display belong to the user interface, except for the page you requested displayed in the browser’s main window.

  2. Browser Engine – Passes instructions between the user interface and the rendering engine.

  3. Rendering Engine – is responsible for Rendering the requested content. If the requested content is HTML, it is responsible for parsing the HTML and CSS content and displaying the parsed content on the screen.

    It’s also called a Rendering Engine or Layout Engine.

    By default, the rendering engine displays HTML and XML documents and images. Other types of content can also be displayed through plug-ins (or browser extensions); For example, PDF documents can be displayed using the PDF viewer plug-in. But in this chapter, we’ll focus on its main purpose: to display HTML content and images formatted with CSS.

    Browsers (Firefox, Chrome, and Safari) are built around two rendering engines. Firefox uses Gecko, Mozilla’s “homemade” rendering engine. Safari and Chrome both use WebKit.

    The browser Rendering Engine (Development language) Script Engine (Development language)
    Chrome Blink (c++) V8 (c++)
    Opera Blink (c++) V8 (c++)
    Safari Webkit (c++) JavaScript Core (nitro)
    FireFox Gecko (c++) SpiderMonkey (c/c++)
    Edge EdgeHTML (c++) Chakra JavaScript Engine (c++)
    IE Trident (c++) Chakra JScript Engine (c++)

    In 2017, Firefox launched a new Web engine, Quantum, which is based on the Gecko engine and uses Rust’s concurrency and Servo’s high-performance components to bring more parallelism and GPU computing to Firefox. Make Firefox faster and more reliable.

    In March 2015, Microsoft will scrap its own Edge: it will develop Chromium browser instead.

Browsers are multi-process

Process thread simple understanding: there can be multiple threads in the process, the process is QQ, thread is the session.

  • Browsers are multi-process
  • The browser works because the system allocates resources (CPU, memory) to its processes
  • To put it simply, every time you open a Tab, you create a separate browser process.

Processes in the browser:

  1. Browser process: the main process of the Browser (responsible for coordination and control), there is only one. There are

    • Responsible for browser interface display and user interaction. Forward, backward, etc
    • Responsible for page management, creating and destroying other processes
    • Draw an in-memory Bitmap from the Renderer process onto the user interface
    • Network resource management, download, etc
  2. Third-party plug-in process: Each type of plug-in corresponds to one process, which is created only when the plug-in is used

  3. GPU process: a maximum of one. It is used for 3D drawing

  4. Renderer process (browser kernel) (Renderer process, internally multithreaded)

    • By default, each Tab page has one process and does not affect each other.
    • The main function is page rendering, script execution, event processing and so on

The rendering process is multithreaded:

  1. GUI rendering thread

    • Responsible for rendering browser interfaces, parsing HTML, CSS, building DOM trees and RenderObject trees, layout and drawing, etc.
    • This thread executes when the interface needs to be repainted or when some operation causes reflow
    • Note that the GUI rendering thread and the JS engine thread are mutually exclusive, the GUI thread is suspended (frozen) while the JS engine is executing, and GUI updates are stored in a queue until the JS engine is idle.
  2. Js engine thread

    • Also known as the JS kernel, it handles Javascript scripts. (For example V8 engine)
    • The JS engine thread is responsible for parsing Javascript scripts and running code.
    • The JS engine waits for tasks to arrive in the task queue and then processes them, with only one JS thread running on a Tab page (renderer process)
    • Also note that the GUI rendering thread and the JS engine thread are mutually exclusive. So if JS takes too long to execute, it should be placed under the body, otherwise it will block the page rendering load.
  3. Event trigger thread

    • Manages the event queue
    • Listen for events and place the callback function on the event queue when appropriate
  4. Timing trigger thread

    • When setInterval and setTimeout finish timing in this thread, the callback function is placed in the event queue
    • The browser timing counter is not counted by the JavaScript engine (because JavaScript engine is single-threaded, if it is in the blocking thread state, it will affect the timing accuracy), so it is timed and timed by a separate thread (after the timing is finished, it is added to the event queue, waiting for the JS engine to be idle).
    • Note that the W3C specification in the HTML standard requires that setTimeout intervals below 4ms be counted as 4ms.
  5. Asynchronous HTTP request threads

    • When a change in the state of an XHR object is detected, the callback function is placed in the event queue
    • When a state change is detected, if a callback function is set, the asynchronous thread generates a state change event and places the callback in the event queue. It’s executed by the JavaScript engine.

    Take a look at the execution line:

The rendering thread is mutually exclusive with the JS engine thread

Since JavaScript is DOM manipulable, if you render the interface while modifying these element attributes (i.e., the JS thread and the UI thread are running at the same time), the element data obtained before and after the render thread may not be consistent.

Therefore, to prevent unexpected results from rendering, the browser sets the GUI rendering thread and the JS engine to be mutually exclusive. The GUI thread is suspended when the JS engine executes, and GUI updates are stored in a queue until the JS engine thread is idle.

A simple example:

<! DOCTYPEhtml>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="Width = device - width, initial - scale = 1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Document</title>
    <script>
      // Hello World on the page will not turn red
      document.getElementById("app").style.color = "red";
    </script>
  </head>
  <body>
    <div id="app">
      hello world!
    </div>
  </body>
</html>
Copy the code

JS blocks page loading

From the above mutual exclusion, it can be inferred that JS will block the page if it takes too long to execute.

For example, if the JS engine is doing a huge amount of computation, updates to the GUI, if any, will be queued up for execution when the JS engine is idle. However, due to the huge amount of computation, so the JS engine is likely to be idle for a long time, naturally will feel extremely jammed.

Therefore, try to avoid JS execution time is too long, this will cause the page rendering is not coherent, resulting in page rendering load blocking feeling.

To sum up:

  • CSS loading does not block DOM tree parsing (DOM is built as usual for asynchronous loading), but it blocks render tree rendering (wait until CSS is loaded because the render tree needs CSS information)
  • Javascript blocks DOM parsing

The browser’s rendering mechanism

For rendering, the first thing you need to understand is the device refresh rate.

The device refresh rate is the frequency with which the device screen is rendered, or more generally, the screen as a wall, the device refresh rate is how often the wall is repainted. For example, the default refresh rate of mobile phones and computers is 60FPS, which means that the screen renders 60 times in 1s, or about 16.7ms per screen rendering.

This means that the optimal rendering performance of a browser is when all operations are performed in a frame of 16.7ms, and whether this is done in a frame directly determines the sex and user interaction.

The rendering engine will initially fetch the content of the requested document from the network layer, which is generally limited to 8000 blocks.

Then proceed with the basic process as follows:

The rendering engine will start parsing the HTML document and turn each tag into a DOM node on the “content tree.” It also parses style data in external CSS files and style elements. This style information in HTML with visual instructions will be used to create another tree structure: the render tree.

The rendering tree contains multiple rectangles with visual attributes such as color and size. The order in which these rectangles are arranged is the order in which they will appear on the screen.

Once the rendering tree is built, the “layout” phase of processing is entered, where each node is assigned an exact coordinate that should appear on the screen. The next stage is drawing – the rendering engine traverses the rendering tree, drawing out each node from the user interface back-end layer.

It should be emphasized that this is a gradual process. For a better user experience, the rendering engine tries to get the content on the screen as quickly as possible. It doesn’t have to wait until the entire HTML document has been parsed to start building the rendering tree and setting up the layout. While receiving and processing the rest of the content from the web, the rendering engine parses and displays some of it.

The CSSOM tree and DOM tree are combined into a render tree, which is then used to compute the layout of each visible element and output to the rendering process to render the pixels onto the screen. Optimizing each of these steps is critical for optimal rendering performance.

Specific process:

  • The DOM tree is merged with the CSSOM tree to form the render tree.
  • The render tree contains only the nodes needed to render a web page.
  • The layout calculates the exact position and size of each object.
  • The final step is rendering, using the final render tree to render the pixels onto the screen.

Note that visibility: hidden is different from display: None. The former hides the element, but the element still occupies layout space (rendering it as an empty box), while the latter (display: None) completely removes the element from the rendering tree, and the element is neither visible nor part of the layout.

Take webKit rendering as an example:

A real example can be seen using a debugging tool:

Processing of script tags

JS can manipulate the DOM to modify the DOM structure, and CSSOM can manipulate the node style. This causes the browser to immediately stop parsing the HTML when it encounters script (CSS does not), execute JS, and return control.

In fact, JS doesn’t just stop parsing HTML before it executes; it must wait for CSS parsing to complete. When a browser encounters a script element and finds that the CSS in front of the element has not been parsed, it will wait for the CSS to be parsed before executing JS.

JS blocks HTML parsing and CSS parsing. The entire parsing process must wait for JS execution to complete before it can continue. This is called JS blocking the page. A script tag, which delays DOM generation, CSSOM generation, and all subsequent rendering, makes sense from a performance perspective to place script at the bottom of the page.

Simply put: The render thread and the JS engine thread are mutually exclusive, the render thread is suspended (frozen) while the JS engine is executing, and the render update is stored in a queue until the JS engine is idle.

To sum up:

The browser’s rendering process is divided into:

  • The DOM tree to build
  • CSSOM tree building
  • RenderObject tree building
  • layout
  • draw

Rearrange reflow with repaint

Rearrangement reflow

Reflow refers to recalculating the page layout.

A node reflow recalculates the size and position of the node, and may trigger reflows for its children, ancestors, and other nodes on the page. After that, repaint is triggered again.

When part (or all) of the Render Tree needs to be rebuilt due to changes in element size, layout, hiding, etc. This is called backflow, and each page needs to backflow at least once, the first time the page loads.

Cause reflow operation

  • Resize the window
  • Change the font
  • Add or remove stylesheets
  • Content changes, such as the user entering text in an input box
  • Activate CSS pseudo-classes, such as hover (IE for sibling pseudo-classes)
  • Manipulating class attributes
  • Script manipulation of DOM
  • Calculate the offsetWidth and offsetHeight properties
  • Sets the value of the style property

Some CSS properties that trigger a page layout

  • Box model attributes trigger relayouts
    • width
    • height
    • padding
    • margin
    • display
    • border-width
    • border
    • min-height
  • Location properties and floats also trigger relayouts
    • top
    • bottom
    • left
    • right
    • position
    • float
    • clear
  • Changing the text structure inside a node also triggers a relayout
    • text-align
    • overflow-y
    • font-weight
    • overflow
    • font-family
    • line-height
    • vertical-align
    • white-space
    • font-size

Redraw repaint

Repiant or Redraw traverses all nodes to detect visible style attributes such as visibility, color, outline, and then updates the response portion of the page based on the results.

When some elements in the Render Tree need to update their attributes, these attributes only affect the appearance and style of the elements, not the layout, such as background-color. It’s called redrawing

Some CSS properties that trigger redraw but not rearrangement:

  • color
  • border-style,border-radius
  • visibility
  • text-decoration
  • background,background-image,background-position,background-repeat,background-size
  • outline,outline-color,outline-style,outline-width
  • box-shadow

Example:

var bstyle = document.body.style; // cache

bstyle.padding = "20px"; // reflow, repaint
bstyle.border = "10px solid red"; // Reflow and repaint again

bstyle.color = "blue"; // repaint
bstyle.backgroundColor = "#fad"; // repaint

bstyle.fontSize = "2em"; // reflow, repaint

// new DOM element - reflow, repaint
document.body.appendChild(document.createTextNode('dude! '));
Copy the code

Of course, the browser is smart enough not to reflow or repaint every time it makes a style change like the one above. Typically, browsers accumulate a batch of these operations and do a reflow, also known as asynchronous or incremental asynchronous reflow. But there are cases where browsers don’t do this, such as resize Windows, changing the default font on a page, and so on. For these operations, the browser reflow immediately.

Reduce redrawing and rearrangement:

Redraw and backflow are very difficult to avoid in real development, and the best thing to do is to minimize the occurrence of this behavior.

  • Js should try to minimize access to DOM nodes and CSS attributes, and try not to add, modify or delete elements too frequently, because this may frequently lead to page reflow. You can first remove the DOM node to the memory for complex operations and then display it on the page. (DOM)

  • Reduce unnecessary DOM depth. Changing one level in the DOM tree causes changes at all levels, up to the root and down to the children of the changed node. This results in a lot of time spent executing reflow.

  • Do not change the style of the child element through the parent. It is better to change the style of the child element directly. Changing the style of the child element does not affect the size and size of the parent and sibling elements as much as possible

  • Try to style elements by class, rather than using style to manipulate a single attribute multiple times

    // bad
    var left = 10,
    top = 10;
    el.style.left = left + "px";
    el.style.top  = top  + "px";
    
    // Good
    el.className += " theclassname";
    
    // Good
    el.style.cssText += "; left: " + left + "px; top: " + top + "px;";
    Copy the code
  • If possible, use fixed or absolute positions for the HTML elements that generate the animation, the modified CSS will not be Reflow.

  • The img tag is set to a height and width to reduce redrawing and rearrangement

  • Taking the DOM offline and modifying it, such as taking a DOM out of the document stream, such as display: None, and modifying the property, only one backflow occurs.

  • Try to use transform to do deformation and displacement without causing backflow

  • Tradeoff speed smoothness. For example, implementing an animation that moves by 1 pixel is the smoothest, but reflow will be too frequent and the CPU will soon be completely consumed. It’s much better if you move it by 3 pixels.

  • Another reason not to use tables layouts is that a reflow triggered by one element in tables causes all other elements in the table to reflow. When table is suitable, you can set table-layout to auto or fixed.

  • Avoid unnecessarily complex CSS selectors, especially descendant selectors, which consume more CPU to match.

PS: display: None will trigger reflow, and visibility: Hidden will only trigger repaint because no position change is found.

To sum up:

Rearrangement: Elements are changed in size and position

Redraw: The color, background, border, and outline of the element are changed, but the geometry of the element remains the same.

Reflow costs much more than Repaint. Every node in a DOM Tree has a reflow method, and a node’s reflow is likely to result in reflows for its children, or even its parents, and siblings. On some high-powered computers this may not be a problem, but if reflow occurs on mobile phones, the process can be very painful and power-hungry.

Causes of slow page loading

Browser section

  • The network layer

    1. Excessive HTTP requests

      When you open a web page, it doesn’t take much time for the daemon to respond. The waiting time is spent downloading web elements, namely HTML, CSS, JavaScript, Flash, images, etc. It is estimated that each additional element increases the load time of a web page by 25-40 milliseconds (depending on the user’s bandwidth).

    2. The resource access bandwidth is small

      Two aspects, one is the client bandwidth, the other is the server bandwidth.

    3. Page elements (images, videos, styles) are too large

  • Browser Rendering layer

    1. Render blocking:

      Browsers need to build DOM and CSSOM trees to render a page, and if HTML and CSS file structures are large and complex, this can have a serious impact on page loading speed.

      The so-called rendering blocking resource means that the request for the resource needs to be made before the corresponding DOM tree or CSSOM tree is built. This behavior obviously delays the start time of the rendering operation.

      JS blocking vs. CSS blocking:

      HTML, CSS, and JavaScript are all resources that block rendering. HTML is required (rendering is impossible without DOM), but you can also optimize CSS and JavaScript to minimize blocking.

    2. Repeat apply colours to a drawing

    3. The DNS

  • Server level

    1. Low hardware configuration: This is bidirectional
    2. Server software, such as firewalls and Intranet policies
    3. No configuration optimization for Web servers such as Nginx
    4. The CPU is full or the database is not optimized. Procedure
    5. Code issues, code efficiency, code performance
    6. Contains a plethora of analysis class tools

Code section

  • Build level

    Code is not packaged, compressed, or optimized for compatibility.

    Duplicate requests, code not merged.

  • Code level

    No good coding habits, wrong arrangement of JS and CSS

    For loop, iterate, synchronize, redirect, block requests

    Duplicate, useless code is not removed

    Did not reconstruct the code with complex logic business, understood the design pattern, and sorted out the business

  • SSR, 英文Server Side Render

    Async is not added

    Not thinking about page loading, user experience

  • specification

    The CSS specification

    HTML specification /HTML5 specification

    Airbnb code specification, etc.