Analysis of the principle of event loop (even loop)

1. To understand the event loop, you must first understand threads and processes

     Usually, a process can contain several threads, and they can use the resources owned by the process. In the operating system that introduces threads, the process is usually used as the basic unit of resource allocation, and the thread is used as the basic unit of independent operation and independent scheduling. Since threads are smaller than processes and basically do not own system resources, the overhead for their scheduling will be much smaller, and the degree of concurrent execution among multiple programs in the system can be improved more efficiently.

2. The browser is a multi-process and multi-thread application, and its internal work is very complicated. Its processes mainly include the browser process, the network process, and the rendering process.

      ① Browser process: responsible for the display and operation of the BOM interface, monitoring the forward and backward operations of the browser, and other processes rely on the browser process for startup and other thread-dependent startup

      ② Network process: mainly responsible for network communication, network resource loading, etc.

      ③ Rendering process: After startup, a rendering main thread will be started first, and all front-end codes will be executed on the rendering main thread. The browser will open a rendering process for all tab pages (process isolation, which is why Google Chrome takes up a lot of memory. If you are interested, you can read Google’s official documentation. It is said that one process per site may be used in the future to reduce the number of processes.) This is to ensure that all tab pages do not affect each other. The main rendering thread is the busiest thread in the browser. The tasks that need to be processed include but are not limited to parsing HTML, parsing CSS, calculating styles, layouts, and processing layers. Callback functions, etc.

       At this time, everyone may think, since the rendering process needs to deal with so many things, why not open multiple threads? I don't know either. I didn’t find out why. There may be certain technical barriers. If you know, you can leave me a message to communicate.

3. The rendering process needs to handle so many things, how to schedule tasks specifically?

       For example, ten lines of code that are currently executing a JS function in the middle of the execution have run to the fifth line. At this time, what should I do if a button clicked by the user is to suspend the execution of this code and execute the user's click event immediately, or after executing this function, then execute the click event? In fact, the browser has done a very ingenious process on this, which is to queue up orderly tasks one by one for execution, and thus the message queue is born. The message queue is also called the event queue, so the event loop mainly occurs in the rendering main thread. As shown in the picture:

ee686d5134484a7a97ea334eae30f4f4.png

       It is easy to understand the rendering logic through the source code of the Chrome browser. At the very beginning, the for (;;) written in the startup function of the rendering main thread indicates that the loop condition is always true

c3ce071d48ff4fa4914fab543be4a2ec.png

Screenshot of browser source code

8615d30894c24f40a615f0600816225a.png

       Each cycle will call next_work_info to check whether there is a task in the message queue. If there is, the first task will be taken out and executed. After execution, it will enter the next cycle. If there is no task, it will enter the dormant state. This is the core content of the event cycle.

ps: Google calls it a message loop, message loop, and the W3C standard calls these event loops, which are actually one thing.

4. But knowing these things is not enough. You also need to know some details in the event loop. Next, I will further explain these small details, which may give you a better understanding of the event loop.

① Synchronization

    During the execution of the code, some tasks that cannot be executed immediately, such as setTimeout(fn, 3000), AJAX, AddEventListener, etc., will cause the main thread to be blocked. If the main thread has been waiting for these tasks to be executed one by one, it will cause many problems. For example, html css drawing and other js loading resource loading will be blocked, causing the browser to crash. This is what is often called synchronization.

bb4cbc61602240728c663f0baab49377.png

② asynchronous

    Since the rendering main thread undertakes this extremely important task, it can never be blocked. In order to prevent blocking, the browser chooses asynchronous solution

5197f6e1351648ae95c5cd09dd074412.png

    You should know that tasks are not prioritized. In the message queue, the first-in-first-out principle is followed, but the message queue has priority.

Interpreted according to W3C standards

① Each task has a task type. Tasks of the same type must be in the same queue. Different tasks can belong to different queues.

②In each event cycle, the browser can take out tasks from different queues for execution according to the actual situation.

    With the rapid increase in the complexity of browsers, W3C no longer uses the macro queue, and the main way to add it to the micro queue is to use Promise and MutationObserver.

For example:

//立即把一个函数添加到微队列
 Promise.resolve().then(fn)

1. First execute the rendering main thread, which is actually calling the synchronization code in the call stack, and the system will execute it first

2. After the rendering main thread completes all synchronization tasks in the call stack, the event loop starts to execute at this time

3. After the rendering main thread finds that the call stack is empty, it will perform an event loop to observe the event callback to be executed. At this time, it will enter the micro-queue, and the event loop detects that there is an event in the micro-queue, and then performs the operation we mentioned above, and then takes out the relevant event task and puts it into the call stack, which is executed by the main thread.

4. After the execution of the micro-queue is completed, start to call the tasks in the delay queue, and finally check whether there are tasks in the interactive queue, execute them if they exist, and enter the dormant state if they do not.

Summarize the event loop of JS

    The event loop is also called the message loop, which is the way the browser renders the main thread. In the source code of Chrome, it opens a for loop that will not end. Each loop takes 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 an appropriate time.

    In the past, message queues were simply divided into macro queues and micro queues. This statement can no longer satisfy the complex browser environment, and a more flexible and changeable processing method has been replaced. According to the official W3C explanation, each task has a different type, and 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 to take. But the browser must have a micro-queue, and the tasks of the micro-queue must have the highest priority and must be scheduled and executed first.

Related Interview Questions

How to understand the asynchrony of JS

Reference answer:

    JS is a single-threaded language, because it runs in the main rendering thread of the browser, and there is only one main rendering thread and the main rendering thread undertakes many tasks, such as rendering pages, executing JS, parsing htmlcss, and executing event callbacks. If you use a synchronous method, it is very likely that the main thread will be blocked, which will cause many other tasks in the message queue to be unable to be executed. In this way, on the one hand, the busy main thread will waste time in vain, and on the other hand, the page cannot be updated in time, causing the user to be stuck.

    So the browser uses an asynchronous way to avoid it. The specific method is that when certain tasks occur, such as timers, networks, and event monitoring, the main thread will hand over the tasks to other threads for processing, and immediately end the execution of the tasks by itself, and then execute subsequent codes. When other threads are finished, wrap the callback function passed in advance into a task, add it to the end of the message queue, and wait for the main thread to schedule execution. In this asynchronous mode, the browser never blocks, thus ensuring the smooth operation of the single thread to the greatest extent.

Can the timer in JS achieve accurate timing? Why?

Reference answer:

No, because:

1. Computer hardware does not have an atomic clock, so accurate timekeeping cannot be achieved.

2. The timing function of the operating system itself has a small amount of deviation. Because the timer of JS finally calls the function of the operating system, it also carries these deviations.

3. According to the W3C standard, when the browser implements the timer, if the nesting level exceeds 5 layers, it will have a minimum time of 4 milliseconds, which will cause a deviation when the timing time is less than 4 milliseconds

4. Affected by the event loop, the callback function of the timer can only run when the main thread is idle, so it brings a deviation

Guess you like

Origin blog.csdn.net/2303_76218115/article/details/129211284