preface

In the era of mobile Internet, users have higher and higher requirements for the speed of opening web pages. According to the research of Baidu User Experience Department, the relationship between page abandonment rate and page opening time is shown in the figure below.

chart

According to the research results of Baidu user experience Department, the average user expects and can accept the page loading time is less than 3 seconds. If the page load time is too slow, users will get impatient and leave.

The importance of the first screen as the first screen to face the user is self-evident. Optimizing user experience is one of the things we really need to focus on in front end development.

In this article, we discuss the browser rendering process and performance optimization with 8 interview questions.

Let’s start with these 8 questions to understand the browser rendering process, which will be solved later

  1. Why is Javascript single threaded?

  2. Why does JS block page loading?

  3. Does CSS loading block?

  4. What’s the difference between DOMContentLoaded and Load?

  5. What is CRP, or Critical Rendering Path? How to optimize?

  6. What’s the difference between Defer and async?

  7. What about browser backflow and redraw?

  8. What is a Composite?

Processes and Threads

Processes and threads are basic concepts of the operating system.

A process is the smallest unit of CPU resource allocation (the smallest unit that can hold resources and run independently).

A thread is the minimum unit of CPU scheduling (it is a single run unit based on a process).

process_thread

Modern operating systems are capable of multitasking, such as surfing the Web with a browser and listening to music at the same time.

For an operating system, a task is a process. For example, opening a browser starts a browser process, and opening a Word starts a Word process.

Some processes do more than one thing at a time, such as Word, which can type, spell check, print, and so on. To do more than one thing at a time within a process requires multiple “subtasks” to run simultaneously. These “subtasks” within a process are called threads.

Since each process must do at least one thing, a process must have at least one thread. The system allocates separate memory to each process, so the process has its own resources. Each thread in the same process shares the memory space of the process (including code segments, data sets, heap, etc.).

To use a vivid metaphor, a process is like a production plant with borders, while threads are like employees within the plant, doing their own things or collaborating with each other to do the same thing.

When we start an application, the computer creates a process, and the operating system allocates a portion of memory to the process, where all of the application’s state is stored.

The application may also create multiple threads that can share data in this part of memory to help it work. If the application is shut down, the process is terminated and the operating system frees the memory.

process_thread_example

The browser’s multi-process architecture

A good program is often divided into several separate but compatible modules, and the same is true of browsers.

Chrome, for example, is made up of multiple processes, each with its own core responsibilities, that work together to complete the overall function of the browser,

Each process contains multiple threads, and multiple threads within a process will also work together to complete the responsibilities of the process.

Chrome uses a multi-process architecture, with a Browser process at the top to coordinate the Browser’s other processes.

process

advantages

By default, every TAB opens a new process, so a single TAB crash does not affect the entire browser.

Similarly, a third-party plugin crash does not affect the entire browser.

Multiple processes can take full advantage of modern cpus with multiple cores.

It is easy to use sandbox models to isolate processes such as plug-ins and improve browser stability.

disadvantages

The system allocates memory and CPU resources to new browser processes, so the memory and CPU resource consumption is higher.

But Chrome does a good job of freeing up basic memory that can be quickly freed up for other programs to run.

The main processes and responsibilities of the browser

process_list

Main Process Browser Process

Responsible for browser interface display and interaction. Manage individual pages, create and destroy other processes. Network resource management, download and so on.

Plugin Process

Each type of plug-in corresponds to a process that is created only when the plug-in is in use.

GPU Process INDICATES the GPU Process

At most one, for 3D rendering, etc

Renderer Process

Called the browser rendering process, or browser kernel, it is multi-threaded internally. Mainly responsible for page rendering, script execution, event processing, etc. (This paper focuses on analysis)

Rendering process (browser kernel)

The browser’s rendering process is multi-threaded, so let’s take a look at the main threads:

renderder_process

1. GUI rendering thread

  • Responsible for rendering the browser interface, parsing HTML,CSS, building DOM and RenderObject trees, layout and rendering, etc.

  • This thread executes when the interface needs to be repainted or when some operation causes reflow.

  • Note that the GUI rendering thread is mutually exclusive with the JS engine thread, the GUI thread is suspended while the JS engine is executing, and GUI updates are stored in a queue until the JS engine is idle and executed immediately.

2. JS engine threads

  • The Javascript engine, also known as the JS kernel, handles Javascript scripts. (e.g. V8 engine)

  • The JS engine thread is responsible for parsing the Javascript script and running the code.

  • The JS engine waits for the arrival of tasks in the task queue and then processes them. Only one JS thread is running the JS program in a Tab (renderer process) at any time.

  • Note that the GUI rendering thread and the JS engine thread are mutually exclusive, so if the JS engine takes too long to execute, it will cause the rendering of the page to be incoherent and block the page rendering load.

3. Event triggering thread

  • It belongs to the browser, not the JS engine, and is used to control the event loop.

  • When the JS engine executes a code block such as setTimeOut (or from other threads in the browser kernel, such as mouse clicks, AJAX asynchronous requests, etc.), it adds the corresponding task to the event thread

  • When the corresponding event is triggered according to the triggering condition, the thread will add the event to the end of the queue to be processed, waiting for the JS engine to process

  • Note that due to the single-threaded nature of JS, the events in the queue are queued for the JS engine to process (only when the JS engine is idle).

4. Timing trigger thread

  • The thread where the legendary setInterval and setTimeout reside

  • The browser timing counter is not counted by the JavaScript engine (because the JavaScript engine is single-threaded, if you are in a blocked thread state, it will affect the accuracy of the timing)

  • Therefore, the timer is timed and triggered by a separate thread (after the timer is finished, it is added to the event queue, waiting for the JS engine to idle).

  • Note that the W3C states in the HTML standard that any interval of less than 4ms in setTimeout is required to count as 4ms.

5. Asynchronous HTTP request threads

  • After the XMLHttpRequest is connected, it opens a new thread request through the browser.

  • When a state change is detected and a callback function is set, the asynchronous thread generates a state change event and places the callback in the event queue. This is then executed by the JavaScript engine.

Browser Rendering Process

If we had to talk about what happened between the input URL and the page loading, it would be endless… Let’s just talk about the browser rendering process here.

workflow
  1. The HTML file is parsed and the DOM tree is built, while the main browser process downloads the CSS file

  2. After the CSS file is downloaded, parse the CSS file into a tree-shaped data structure, and then combine with the DOM tree to merge the RenderObject tree

  3. RenderObject tree (Layout/reflow), responsible for the RenderObject tree elements size, location, etc

  4. Draw the RenderObject tree (paint), drawing the pixel information of the page

  5. The browser main process gives the default layers and composite layers to the GPU process, which then composes the layers to display the page

Answer key

1. Why should Javascript be single threaded?

This is because of the mission of Javascript as a scripting language! JavaScript to deal with the user interaction in the page, as well as the manipulation of DOM tree, CSS style tree to present users with a dynamic and rich interactive experience and server logic interactive processing.

If JavaScript manipulates these UI DOMS in a multi-threaded manner, conflicts of UI operations may occur.

If Javascript is multithreaded, the DOM node in the UI can become a critical resource under multithreaded interaction,

Suppose there are two threads working on a DOM simultaneously, one for modification and one for deletion. It is up to the browser to decide which thread’s execution results should take effect.

Of course we can solve the above problem by locking. But in order to avoid further complexity with the introduction of locks,Javascript initially opted for single-threaded execution.

2. Why does JS block page loading?

Since JavaScript manipulates the DOM, if the interface is rendered while modifying these element attributes (i.e., the JavaScript thread and the UI thread are running simultaneously), then the element data obtained before and after the rendering thread may be inconsistent.

So to prevent unexpected results from rendering, the browser sets the GUI rendering thread to be mutually exclusive with the JavaScript engine.

GUI threads are suspended while the JavaScript engine is executing, and GUI updates are kept in a queue until they are executed as soon as the engine thread is idle.

From the above we can deduce that since the GUI rendering thread and the JavaScript executing thread are mutually exclusive,

When the browser executes a JavaScript program, the GUI rendering thread is stored in a queue until the JS program is completed.

Therefore, if the JS execution takes too long, it will cause the page rendering to be incoherent, resulting in the page rendering load blocking feeling.

3. Does the CSS load block?

From the browser rendering process above, we can see:

DOM and CSSOM are usually built in parallel, so CSS loading does not block DOM parsing.

However, since the Render Tree is dependent on the DOM Tree and CSSOM Tree,

So he has to wait until the CSSOM Tree is built and the CSS resources have been loaded (or failed to load the CSS resources) before he can render.

Therefore,CSS loading blocks Dom rendering.

Since JavaScript manipulates DOM and CSS styles, if the interface is rendered while modifying these element attributes (i.e., the JavaScript thread and the UI thread are running simultaneously), then the element data obtained before and after the rendering thread may be inconsistent.

So to prevent unexpected results from rendering, the browser sets the GUI rendering thread to be mutually exclusive with the JavaScript engine.

As a result, the stylesheet will be loaded and executed before any subsequent JS execution, so the CSS will block the subsequent JS execution.

4. What’s the difference between DOMContentLoaded and Load?

  • When the DOMContentLoaded event is triggered, only after DOM parsing is complete, no stylesheets, images are included. We mentioned earlier that CSS loading blocks Dom rendering and later JS execution, which blocks Dom parsing, so we can conclude that when there is no script in the document, the browser can trigger the DOMContentLoaded event after parsing the document. If the document contains a script, the script blocks parsing of the document, and the script cannot be executed until the CSSOM build is complete. In any case,DOMContentLoaded does not need to wait for other resources, such as images, to load.

  • When the onLoad event is triggered, all the DOM, style sheets, scripts, images, and other resources on the page have been loaded.

  • DOMContentLoaded – > load.

5. What is CRP, or Critical Rendering Path? How to optimize?

The critical rendering path is a series of steps the browser takes to convert HTML CSS JavaScript into pixel content rendered on the screen. This is the browser rendering process we mentioned above.

To do the first render as quickly as possible, we need to minimize the following three variables:

  • Number of critical resources: Resources that may prevent the first rendering of a web page.

  • Critical Path Length: The number of round trips or total time required to obtain all critical resources.

  • Key bytes: The total number of bytes required to achieve the first rendering of a web page, equal to the total size of all key resource transfer files.

1. Optimization of DOM

  • Remove unnecessary code and comments including whitespace and try to minimize the file.

  • You can use GZIP to compress files.

  • Combine HTTP cache files.

2. Optimize the CSSOM

Shrinking, compression, and caching are also important. CSSOM was mentioned earlier that it prevents page rendering, so we can optimize for that.

  • Reduce the number of key CSS elements

  • When we declare stylesheets, pay close attention to the types of media queries that can significantly affect CRP performance.

3. The optimized JavaScript

When the browser encounters aScript tag, it prevents the parser from continuing until the CSSOM is built, then JavaScript will run and continue the DOM build process.

  • Async: After we add async property to the script tag, the browser will continue parsing the DOM when it encounters the script tag, and the script will not be blocked by CSSOM, that is, CRP.

  • Defer: Differs from Async in that the script needs to execute until after the document is parsed (before the DOMContentLoaded event), whereas async allows the script to run in the background while the document is parsed (the download doesn’t block the DOM, but the execution does).

  • Async is recommended when our script does not modify the DOM or CSSOM.

  • Preload — preload & Prefetch.

  • DNS prefetch — dns-prefetch.

conclusion

  • We analyzed and described our CRP in terms of critical resources, key bytes, critical path length.

  • Minimize the number of critical resources: eliminate them (inline), defer their download, or have them resolved asynchronously (async), and so on.

  • Optimize key bytes (shrink, compress) to reduce download time.

  • Optimize the order in which remaining critical resources are loaded: have critical resources (CSS) downloaded early to reduce CRP length.

Critical path rendering optimization for front-end performance optimization

6. What’s the difference between defer and async?

When the browser hits a script:

1. <script src=”script.js”>

Without defer or async, the browser loads and executes the specified script immediately. “Immediately” means before rendering the document elements under the script tag, that is, without waiting for the document elements to be loaded later, it loads and executes as soon as it is read.

2. <script async src=”script.js”>

With async, the loading and rendering of subsequent document elements takes place in parallel with the loading and execution of script.js (asynchronously).

3. <script defer src=”myscript.js”>

With Defer, the loading of subsequent document elements will take place in parallel (asynchronously) with the loading of script.js, but the execution of script.js will be completed after all elements have been parsed but before the DOMContentLoaded event is triggered.

From a practical point of view, it is a best practice to throw all scripts into </body> first, since this is the only optimization option for older browsers, which ensures that all other non-scripted elements are loaded and parsed as quickly as possible.

Next, let’s look at a picture:

defer_async

The blue line represents network read and the red line represents execution time, both of which are for scripts. The green line represents HTML parsing.

Therefore, we can come to the conclusion that:

  1. As defer and async read (download) on the network are the same, both are asynchronous (compared to HTML parsing)

  2. The difference between the two lies in when the script is executed after it is downloaded, and obviously defer is the closest we can get to our request for the application script to load and execute

  3. What this figure doesn’t do as much as defer is to take advantage of the fact that it executes the script in the order it was loaded

  4. Async, on the other hand, is a master that executes out of order, because the scripts are loaded and executed right next to each other, so no matter what order you declare it, it executes as soon as it’s loaded, right

  5. If you think about it,async is not very useful for application scripts because it doesn’t allow for dependencies at all (even at the lowest level of sequential execution), but it’s great for scripts that don’t depend on or are not dependent on by any script

Difference from Defer and async — Nightire answers

7. Talk about browser backflow and redraw

Reflux will inevitably cause redrawing, and redrawing will not necessarily cause reflux.

Reflux (Reflow)

When the size, structure, or attributes of some or all of the elements in the Render Tree change, the browser rerenders part or all of the document, a process known as reflux.

Operations that cause reflux:

First page rendering

The browser window size has changed

Element content changes (amount of text, image size, etc.)

Element font size changes

Add or remove visible DOM elements

Activate CSS pseudo-classes (e.g. : :hover)

Query certain properties or call certain methods

Some common properties and methods that cause reflux:

ClientWidth, clientHeight, clientTop, clientLeft



OffsetWidth, offsetHeight, offsetTop, offsetLeft



ScrollWidth, scrollHeight, scrollTop, scrollLeft



ScrollIntoView (), scrollIntoViewIfNeeded ()



getComputedStyle()



getBoundingClientRect()



scrollTo()

Copy the code

Redraw (Repaint)

When the style change of an element in the page does not affect its position in the document flow (for example: color, background-color, visibility, etc.), the browser assigns the new style to the element and redraws it. This process is called redrawing.

Performance impact

Reflux is more expensive to draw.

Sometimes even if a single element is refluxed, its parent and any other elements that follow it will also refluxed. Modern browsers will optimize the reflux or redrawn frequently: the browser will maintain a queue, put all cause re-flow and re-paint operation in the queue, if the number of tasks in the queue or interval reached a threshold, the browser will queue to empty, a batch, so that you can make multiple re-flow and re-paint again.

When you access the following properties or methods, the browser immediately clears the queue:

ClientWidth, clientHeight, clientTop, clientLeft





OffsetWidth, offsetHeight, offsetTop, offsetLeft





ScrollWidth, scrollHeight, scrollTop, scrollLeft





Width, height,





getComputedStyle()





getBoundingClientRect()

Copy the code

Because there may be actions in the queue that affect the value returned by these properties or methods, even if the information you want to retrieve has nothing to do with the changes in the queue, the browser will force you to clear the queue to make sure you get the most accurate value.

How to avoid

CSS
  • Avoid the table layout.

  • Change classes as far as possible at the end of the DOM tree.

  • Avoid setting multiple inline styles.

  • Apply the animation effect to an element whose position attribute is Absolute or fixed.

  • Avoid CSS expressions (e.g., calc()).

Javascript
  • To avoid frequent manipulation of styles, it is better to override the style property once, or define the style list as class and change the class property once.

  • To avoid frequent DOM manipulation, create a documentFragment, apply all DOM manipulation to it, and then add it to the document.

  • You can also set display: None to the element and display it after the operation is over. Because DOM operations on elements with the display attribute none do not cause reflow and redraw.

  • Avoid reading properties that cause reflow/redraw too often, and if you do need to use them more than once, cache them with a single variable.

  • Use absolute positioning for elements with complex animations to take them out of the document stream, otherwise causing frequent backflow of the parent and subsequent elements.

8. What is a Composite?

Render layer merge, where Paint on DOM elements of a page is done on multiple layers.

After completing the drawing process on each layer, the browser will send the drawn bitmap to the GPU to be drawn on the screen, and all layers will be combined into one layer in a reasonable order, and then rendered on the screen.

This process is especially important for pages with overlapping elements, because if the layers are merged in the wrong order, the elements will appear abnormally.

composite

RenderLayers, which is responsible for the corresponding DOM subtree.

The GraphicsLayers graph layer, which is responsible for corresponding to the RenderLayers subtree.

RenderObjects maintain the tree structure. A RenderObject knows how to draw the contents of a node by making the necessary draw calls to a graph context to draw nodes.

Each have a GraphicsContext GraphicsLayer, GraphicsContext layer is in charge of the output of the bitmap, the bitmap is stored in Shared memory, as uploaded to the GPU texture, finally by the GPU will concentrate bitmaps for synthesis, and then the draw We go to the screen, and at this point, our page is on the screen.

The responsibility of the GraphicsContext is to draw pixels to the screen (the process of writing pixel-level data to a bitmap before displaying it to the display). In Chrome, the context is wrapped in Skia (Chrome’s own 2D graphics library).

Some special rendering Layers will be called Compositing Layers, which will have a separate GraphicsLayer, while any rendering layer that is not a Compositing layer will share one with its first parent layer that has a GraphicsLayer.

Advantages of synthetic layer

Once the renderLayer is upgraded, the compositing layer will have its own drawing context and hardware acceleration will be turned on to improve performance.

  • The bitmap of the composition layer will be synthesized by GPU, which is faster than CPU processing (after being promoted to the composition layer, the bitmap of the composition layer will be processed by GPU, but please note that only the processing of the composition layer (combining the output of the bitmap of the drawing context) requires GPU, while the processing of generating the bitmap of the composition layer (the work of the drawing context) is required The CPU.

  • When repaint is needed, only repaint is needed and no other layers are affected (when repaint is needed, only repaint is needed and no other layers are affected). Layout, that means that even if the composition layer is just repaint itself, the style and layout itself take a lot of time.

  • For the Transform and opacity effects, layout and paint are not triggered. (Only the transform and opacity effects do not trigger layout and paint; the other properties are uncertain.)

Normally an element with hardware acceleration turned on becomes a compositing layer that is independent of the normal document stream and can be changed to avoid redrawing the entire page and improve performance.

Be careful not to abuse GPU acceleration, and be sure to analyze its actual performance. Because gPU-accelerated creation of rendering layers comes at a cost, every time a new rendering layer is created, it means new memory allocation and more complex layers to manage. In addition, due to the limited bandwidth of the GPU and CPU on the mobile end, when too many rendering layers are created, the composition will consume more time, which will lead to more power consumption and memory usage. The overhead of too many rendering layers can have an even greater impact on the performance of a page than any performance improvement.

Here do not say in detail, interested children’s shoes to recommend the following three articles ~

Accelerated Rendering in Chrome

CSS GPU Animation: Doing It Right

Wireless performance optimization: Composite

reference

The most complete! Illustrate how a browser works

From browser multi-process to JS single thread, JS running mechanism is the most comprehensive comb

Afterword.

If you like front end like me, also love to do STH, welcome to pay attention to me to play together ~ ❤️

Github address, welcome to follow

blog

My blog, click star, don’t get lost ~

The public,

Front end moment

Front end moment