Event loopEventloop

Event Loop

Browser process model

What is a process?

A program needs its own dedicated memory space to run. This memory space can be simply understood as a process.


Each application has at least one process, and the processes are independent of each other. Even if they want to communicate, both parties need to agree.

What is a thread?

Once you have a process, you can run the program’s code.

The “person” running the code is called a “thread”.

A process has at least one thread, so after the process is started, a thread is automatically created to run the code. This thread is called the main thread.

If the program needs to execute multiple blocks of code at the same time, the main thread will start more threads to execute the code, so a process can contain multiple threads.

image-20220809210859457

What processes and threads does the browser have?

The browser is a multi-process and multi-thread application

The inner workings of browsers are extremely complex.

In order to avoid mutual influence and reduce the chance of serial crashes, when the browser is started, it will automatically start multiple processes.

image-20220809213152371

You can view all current processes in the browser’s task manager

Among them, the most important processes are:

  1. browser process

    Mainly responsible for interface display, user interaction, sub-process management, etc. Multiple threads will be started inside the browser process to handle different tasks.

  2. network process

    Responsible for loading network resources. Multiple threads will be started inside the network process to handle different network tasks.

  3. Rendering process (the process focused on in this lesson)

    After the rendering process is started, a rendering main thread will be started. The main thread is responsible for executing HTML, CSS, and JS codes.

    By default, the browser will start a new rendering process for each tab to ensure that different tabs do not affect each other.

    This default mode may change in the future. Interested students can refer to the official chrome documentation.

How does the main rendering thread work?

The main rendering thread is the busiest thread in the browser. The tasks it needs to handle include but are not limited to:

  • Parse HTML
  • Parse CSS
  • calculation style
  • layout
  • Work with layers
  • Draw the page 60 times per second
  • Execute global JS code
  • Execute event handler function
  • Execution timer callback function

Question: Why doesn’t the rendering process use multiple threads to handle these things?

To handle so many tasks, the main thread encountered an unprecedented problem: how to schedule tasks?

for example:

  • I am executing a JS function, and the user clicks the button halfway through execution. Should I immediately execute the handler function for the click event?
  • I am executing a JS function, and a timer reaches the time halfway through execution. Should I execute its callback immediately?
  • The browser process notifies me that “the user clicked the button”. At the same time, a timer has also expired. Which one should I handle?

The main rendering thread came up with a brilliant idea to deal with this problem: queuing

image-20220809223027806

  1. At the beginning, the main rendering thread will enter an infinite loop
  2. Each loop will check whether there is a task in the message queue. If there is, take out the first task and execute it, and enter the next cycle after executing one; if not, enter the sleep state.
  3. All other threads (including threads from other processes) can add tasks to the message queue at any time. New tasks are added to the end of the message queue. When adding a new task, if the main thread is in a dormant state, it will be awakened to continue fetching tasks in a loop

In this way, each task can be carried out in an orderly and continuous manner.

The entire process is called the event loop (message loop)

Some explanations

What is asynchronous?

During the execution of the code, you will encounter some tasks that cannot be processed immediately, such as:

  • Tasks that need to be performed after the timing is completed – setTimeout, setInterval
  • Tasks that need to be performed after network communication is completed – XHR, Fetch
  • Tasks that need to be performed after user operation – addEventListener

If the main rendering thread is allowed to wait for the timing of these tasks to arrive, it will cause the main thread to be in a “blocked” state for a long time, causing the browser to “stuck”

image-20220810104344296

The main rendering thread is responsible for extremely important work and cannot be blocked under any circumstances!

Therefore, browsers choose asynchronous to solve this problem

image-20220810104858857

Using asynchronous method, the main rendering thread will never block

Interview question: How to understand the asynchronous nature of JS?

Reference answer:

JS is a single-threaded language because it runs in the browser’s main rendering thread, and there is only one main rendering thread.

The main rendering thread is responsible for a lot of work, including rendering pages and executing JS.

If you use synchronization, it is very likely to cause the main thread to block, resulting in many other tasks in the message queue being unable to be executed. In this way, on the one hand, it will cause the busy main thread to waste time, on the other hand, it will cause the page to be unable to be updated in time, causing the user to get stuck.

So the browser uses an asynchronous method to avoid this. The specific method is that when certain tasks occur, such as timers, networks, and event monitoring, the main thread hands the tasks to other threads for processing, and immediately ends the execution of the tasks and switches to executing subsequent code. When other threads complete, the callback function passed in advance is packaged into a task, added to the end of the message queue, and queued up, waiting for the main thread to schedule execution.

In this asynchronous mode, the browser never blocks, thus ensuring the smooth operation of a single thread to the greatest extent.

Why does JS block rendering?

Look at the code first

<h1>Mr.Yuan is awesome!</h1>
<button>change</button>
<script>
  var h1 = document.querySelector('h1');
  var btn = document.querySelector('button');

  //The time specified by the infinite loop
  function delay(duration) {<!-- -->
    var start = Date.now();
    while (Date.now() - start < duration) {<!-- -->}
  }

  btn.onclick = function () {<!-- -->
    h1.textContent = 'Teacher Yuan is very handsome! ';
    delay(3000);
  };
</script>

What happens after you click the button?

Do tasks have priorities?

Tasks have no priority and are first in, first out in the message queue.

But Message queues have priorities

According to the latest explanation from W3C:

  • Each task has a task type. Tasks of the same type must be in the same queue, and tasks of different types can belong to different queues.
    In an event loop, the browser can take out tasks from different queues and execute them according to the actual situation.
  • The browser must prepare a microqueue, and tasks in the microqueue will be executed before all other tasks.
    https://html.spec.whatwg.org/multipage/webappapis.html#perform-a-microtask-checkpoint

As browser complexity increases dramatically, W3C no longer uses macro queues

In the current implementation of chrome, at least the following queues are included:

  • Delay queue: used to store callback tasks after the timer arrives, with a priority of “medium”
  • Interaction queue: used to store event processing tasks generated after user operations, with “high” priority
  • Microqueue: Users store tasks that need to be executed fastest, with the “highest” priority

The main way to add tasks to microqueues is to use Promise and MutationObserver

For example:

// Immediately add a function to the microqueue
Promise.resolve().then(function)

There are many other queues in the browser. Since they have little to do with our development, we will not consider them.

Interview question: Explain the event loop of JS

Reference answer:

The event loop, also called the message loop, is the way the browser renders the main thread.

In Chrome’s source code, it starts a for loop that will not end. Each loop takes out the first task from the message queue for execution, and other threads only need to add the task to the end of the queue at the appropriate time.

In the past, message queues were simply divided into macro queues and micro queues. This statement is no longer able to meet the complex browser environment, and has been replaced by a more flexible and changeable processing method.

According to the official W3C explanation, each task has different types. Tasks of the same type must be in the same queue, and different tasks can belong to different queues. Different task queues have different priorities. In an event loop, the browser decides which queue’s task to take. But the browser must have a microqueue. The tasks in the microqueue must have the highest priority and must be scheduled and executed first.

Interview question: Can the timer in JS achieve precise timing? Why?

Reference answer:

No, because:

  1. Computer hardware does not have atomic clocks and cannot achieve precise timing.
  2. The timing function of the operating system itself has a small amount of deviation. Since the JS timer ultimately calls the function of the operating system, it also carries these deviations.
  3. According to W3C standards, when the browser implements a timer, if the nesting level exceeds 5 levels, it will have a minimum time of 4 milliseconds, which will cause deviation when the timing time is less than 4 milliseconds.
  4. Affected by the event loop, the timer’s callback function can only run when the main thread is idle, thus causing another deviation.