头图

JS blocks rendering, have I understood it wrong for so many years?

卡颂
中文

Hello everyone, I'm Casson.

In the Chinese community, there has been a saying that has been circulating for so many years:

JS thread is responsible for executing JS , GUI The rendering thread is responsible for rendering, the two are mutually exclusive, so JS render.

But with the increasing use of Dev Tools , I gradually began to doubt the above statement. This article will explain why JS block rendering with an actual case.

Welcome to join the human high-quality front-end framework group , with flying

how many threads

In the article explaining the mutual exclusion of JS thread and GUI thread, the threads included in the rendering process are usually listed, such as:

  • GUI Rendering thread
  • JS Engine thread
  • event trigger thread
  • timed trigger thread
  • HTTP request thread

Wait

However, let's take Baidu's search page as an example, open the Performance panel to start recording:

In the recording results above:

  • Chrome_ChildIOThread corresponds to IO thread's task record, user input, network, device-related events are related to him
  • Raster record rasterization thread pool task, GPU record GPU synthesize the thread's task of synthesizing the bitmap, Compositor record 33 tasks above, All three are related to browser rendering
  • Main record tasks in the main thread of the rendering process

From this point of view, the actual thread situation of the browser is not the same as those described in the GUI thread related articles.

main thread tasks

Next, let's go to Main . The gray blocks of different lengths in the red frame are the tasks executed in the main thread.

Pay attention to the green block in the red box FP , which represents First Paint (first drawing):

So what tasks should be performed before the first draw? You can see that there are mainly 3 Task (tasks):

The first task is to request HTML data:

Parse HTML

When the request returns the HTML byte stream, start the second task and parse the HTML byte stream into DOM , the name of this task is as shown in the figure Blue block Parse HTML :

Note that some of them have different execution Evaluate Script , these are the JS code encountered during the parsing DOM tree.

These blocks can be seen from the DOM tree DOM tree generated JS script:

Their presence significantly lengthened the duration of Parse HTML .

Recaculate Style

After parsing the DOM tree (blue Parse HTML ), the next task is purple Recaculate Style :

He is responsible for HTML in CSS style (outreach, inline) output styleSheets , styleSheets has two functions:

  1. Can be combined with DOM tree to bring style to the page
  2. JS can operate styleSheets change page style

We can print from the console document.styleSheets to intuitively feel his existence:

Layout

With DOM tree and styleSheets , then you need to generate a tree for the visible part of the view (for example display: none part does not need to be displayed in this tree ).

This task is purple Layout :

Update Layer Tree

The page that the user sees is actually the result of overlapping multiple pages. Developers can use many means (such as z-index ) to change the level of a certain part.

For example, the scroll bar will form its own independent level:

Since it is a multi-layer structure, you need to update the information of each layer. This task is purple Update Layer Tree :

Paint

We can find that before FP Update Layer Tree , after ---6aafb0fb62e0a37292a5e0dfbf8810e8--- only Paint is left:

Literally, is this drawing ? Not really.

The task of Paint is to organize the drawing information of each layer of pages to form a drawing list, and these data will be handed over to the synthesis thread for subsequent drawing operations.

It can be found that the specific drawing operation is completed by the synthetic thread, and the thread (main thread) where he and JS are located are not mutually exclusive.

Why does JS block rendering

We now know that JS and Paint tasks both happen on the main thread.

The reason why the rendering is blocked is obvious: because the Paint task is not executed in time, that is, the drawing list is not submitted to the compositing thread in time.

The reason why it is not executed in time may be because JS the execution time is too long, resulting in no time for this frame to execute Paint .

For example, we open station B and record the tasks of the main thread.

It can be seen that there is JS the execution time reaches 231.88ms, which exceeds the time of one frame. During this period, the main thread has no time to execute Paint :

Summarize

JS reason why rendering is blocked is because JS execution of rendering-related tasks competes for the limited resources of the main thread.

When JS the execution time is too long, rendering-related tasks have no time to execute.

阅读 3.9k
avatar
卡颂
《React技术揭秘》作者
2.1k 声望
15.8k 粉丝
0 条评论
avatar
卡颂
《React技术揭秘》作者
2.1k 声望
15.8k 粉丝
文章目录
宣传栏