In-depth understanding of the JavaScript event loop mechanism

Source: Internet
Author: User

As we all know, JavaScript is a single-threaded language, although Web-worker is proposed in HTML5, this does not change the core of JavaScript as a single thread. You can see this paragraph in the HTML specification:

To coordinate events, user interaction, scripts, rendering, networking, and so forth, user agents must use event loops as described. There is kinds of event loops:those for browsing contexts, and those for workers.

To reconcile events, user interaction, scripting, UI rendering, and network processing, the user engine must use the event loops. The Event Loop contains two categories: one is based on browsing Context, and the other is based on Worker, which is run independently. In this paper, we use an example to focus on the event loop mechanism based on browsing context.

Take a look at the following JavaScript code:

console.log('script start');setTimeout(function() {  console.log('setTimeout');}, 0);Promise.resolve().then(function() {  console.log('promise1');}).then(function() {  console.log('promise2');});console.log('script end');

First guess what the output order of this code, and then go to the browser console input, see the actual output order and you guess the order is consistent, if consistent, it means that you have the JavaScript event loop mechanism still have a certain understanding, continue to look down can consolidate your knowledge , and if the actual output order is inconsistent with your guess, the following sections of this article will answer your questions.

Task Queue

All tasks can be divided into synchronous tasks and asynchronous tasks, synchronous tasks, as the name implies, is the task of immediate execution, synchronization tasks are generally directly into the main thread execution, and asynchronous tasks, such as the asynchronous task, such as Ajax network requests, setTimeout timing functions are asynchronous tasks, Asynchronous tasks are reconciled through the mechanism of the task queue. Specifically, you can use the following figure to roughly illustrate:

Synchronous and asynchronous tasks go into different execution environments, synchronizing into the main thread, which is the master execution stack, and asynchronously enters the Event Queue. When a task in the main thread finishes executing empty, it goes to the Event Queue to read the corresponding task and pushes the main thread to execute. The constant repetition of the above process is what we call the event loop.

In the event loop, each cycle is called tick, and by reading the specification, the task-handling model for each tick is more complex, and the key steps can be summarized as follows:

    1. Select the first task to enter the queue (oldest task) in this tick, and execute (once) if there is one
    2. Check if there is a microtasks, and if there is, keep executing until the Microtask Queue is emptied
    3. Update Render
    4. The main thread repeats the above steps

You can use a diagram to illustrate the following process:

There are people here who would like to ask, what is microtasks? In the specification, the task is divided into two categories, namely, macro tasks (macros) and micro task (micro tasks), and each macro task, after the end of all the micro-task, here the macro task is also my Some of the tasks that are often said do not differentiate between them, and the task referred to in the following article is considered a macro task.

(macro) Task contains: script (whole code), SetTimeout, setinterval, I/O, UI interaction event, Setimmediate (node. JS Environment)

Microtask mainly includes: Promise, Mutaionobserver, Process.nexttick (node. JS Environment)

APIs such as settimeout/promise are task sources, and the task queue is the specific execution task that they specify. Tasks from different task sources go to different task queues. Among them, setTimeout and setinterval are homologous.

Analyzing Sample Code

It is better to say the words in a clear example. Below we can follow the specification, step-by-step analysis of the above example, first paste the example code (lest you go upside down).

console.log('script start');setTimeout(function() {  console.log('setTimeout');}, 0);Promise.resolve().then(function() {  console.log('promise1');}).then(function() {  console.log('promise2');});console.log('script end');
    1. Overall script as the first macro task into the main thread, encountered Console.log, output script start
    2. When SetTimeout is encountered, its callback function is distributed to the macro task in the Event Queue
    3. Encountering Promise, the then function is assigned to the Micro task event queue, recorded as Then1, and then to the then function, which is divided into the Micro task event queue, recorded as Then2
    4. Encountered Console.log, output script end

At this point, there are three tasks in the Event Queue, such as the following table:

Macro Task Micro Task
SetTimeout Then1
- Then2
    1. Perform micro tasks, first execute then1, output promise1, then execute then2, output promise2, so that all micro tasks are emptied
    2. Perform setTimeout tasks, output setTimeout to this point, the order of output is: script start, Script end, Promise1, Promise2, SetTimeout

So, did you guess right?

Let's see if you know.

One more question, to do an exercise:

console.log('script start');setTimeout(function() {  console.log('timeout1');}, 10);new Promise(resolve => {    console.log('promise1');    resolve();    setTimeout(() => console.log('timeout2'), 10);}).then(function() {    console.log('then1')})console.log('script end');

The topic is a little bit more complicated, and we'll analyze it again:

First, the event loop starts with a macro task (Macrotask) queue, and initially, there is only one scrip T (whole code) task in the macro task queue, and when the task source is encountered, the task is distributed first to the corresponding task queue. So, like the example above, first encountered Console.log, output script start, then go down, Encounter setTimeout task source, distribute it to the task queue, recorded as TIMEOUT1; and then encounter Promise,new promise The code in executes immediately, outputs PROMISE1, then executes resolve, encounters SetTimeout, distributes it to the task queue, notes as Timemout2, then distributes it to the Micro task queue, which is recorded as Then1; and then encounters Console.log Code, direct output script end then check the micro-task queue, found that there is a THEN1 micro-task, execution, output then1 again check the micro-task queue, the discovery has been emptied, then start checking the macro task queue, execute timeout1, output timeout1; then execute TIMEOUT2 , the output timeout2 to this point, all the queues have been emptied and executed. The order of the outputs is: script start, promise1, Script end, Then1, TIMEOUT1, Timeout2

Use the flowchart to see more clearly:


There is a small tip: from the norm, Microtask takes precedence over task execution, so if there is logic that requires precedence, putting the Microtask queue is executed earlier than the task.

Finally, remember,JavaScript is a single-threaded language, and asynchronous operations are placed inside the event loop queue, waiting for the main execution stack to execute, and there is no dedicated asynchronous execution thread. .

Reference documents

This time, thoroughly understand the JavaScript execution mechanism Tasks, microtasks, queues and schedules the JavaScript event loop from a topic

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: and provide relevant evidence. A staff member will contact you within 5 working days.

Tags Index: