JavaScript is a single-threaded, non-blocking scripting language, as anyone who has learned JavaScript knows. Single thread means that JS code is executed at any time, there is only one main thread to handle all the tasks, which means that JS can not be multithreaded programming, but JS has a ubiquitous asynchronous concept, how do we understand? Understanding async and non-blocking depends on the Event Loop (Event Loop). This article focuses on JS threads, synchronous async, task queues and other aspects of the Event Loop.

JS thread

To make it easier for us to understand the event loop, let’s take a quick look at what a JS thread is. If the browser rendering process is multi-threaded, there are mainly the following threads:

  • JS engine thread (main thread) : responsible for parsing JS scripts and running code.

 

  • GUI rendering thread: Responsible for rendering the browser interface, parsing HTML, CSS, constructing DOM and RenderObject trees, laying out and drawing, etc. This thread executes when the interface needs to be repainted or reflow due to some operation.

 

  • Timer trigger thread (setTimeout) : The browser timing counter is not counted by the JS engine, because the JS engine is single-threaded, and if it is in the blocking thread state, it will affect the accuracy of timing. Therefore, it is timed by a separate thread and triggers timing. After the timing is completed, it is added to the event queue and waits for the JS engine to be idle.

 

  • HTTP request thread (AJAX) : after the XMLHttpRequest connection, a new thread requests through the browser. When a state change is detected, if a callback function is set at the same time, the asynchronous thread generates a state change event, puts the callback into the event queue, and then executes it by the JS engine.

 

  • The browser event trigger thread (onclick) is a thread that belongs to the browser, not the JS engine, and is used to control the event loop.

  • The main thread and the render thread are mutually exclusive: the JS engine thread and the GUI render thread are mutually exclusive, the GUI thread is suspended (frozen) while the JS engine is executing, and GUI updates are stored in a queue until the JS engine is idle.

Browser kernel

 

  • EventLoop polls processing threads: We can think of it as an intermediary that communicates between the main thread, the asynchronous thread, and the message queue. As you can see from the main thread clockwise, the whole process is cyclic. Only after the main thread has run out of synchronization code will the queue be checked to see what else needs to be executed.

The main thread gives setTimeout, Ajax, and dom.onclick to three different threads.

 

In the case of setTimeout code, the timer triggers the thread to start timing when it receives the code and to throw the callback function into the message queue when the time is up.

 

2. In the case of Ajax code, the HTTP asynchronous thread immediately initiates an HTTP request and, upon success of the request, throws the callback function into the message queue.

 

3. For dom.onclick, the browser event thread listens to the DOM until the DOM is clicked before throwing the callback into the message queue.

 

Synchronous and asynchronous

 

JS is divided into synchronous tasks and asynchronous tasks:

 

  • Synchronous tasks: queues of tasks that are executed immediately, such as a simple function;

     

  • Asynchronous tasks: Request interfaces to send Ajax, send promises, or time timers, and so on;

Event Queue

 

What is a task queue? Can be understood as a static queue storage structure, following the first in, first out principle: synchronization tasks are executed immediately, into the main thread; Asynchronous tasks are placed in an Event Queue.

 

Macro and micro task queues

 

MacroTask: Overall code Script, UI rendering, setTimeout, setInterval, setImmediate(node.js environment).

 

Microtasks: promise.then (), catch, finally.

 

Difference: The Event loop may have multiple MacroTask queues and only one MicroTask queue.

 

 

MicroTask takes precedence over MacroTask execution, so if there is logic that needs to be executed first, putting it into the MicroTask queue will be executed before MacroTask.

The following code examples give us a good idea of the order in which each task is executed:

Execution stack

MacroTask and MicroTask are both pushed and executed on the stack. JS is a single thread, that is only a main thread, the main thread, there is a stack of each function performs, will generate a new execution context, the execution context will contain some of the current function parameters and local variables, such as information, it will be pushed into the stack, the executing context is always at the top of the stack. When the function completes execution, its execution context is popped from the stack.

conclusion

Synchronous tasks and asynchronous tasks are executed in different execution environments. Synchronous tasks are executed first, and asynchronous tasks are put into a circular queue. After the synchronization task is completed, asynchronous tasks in the queue are executed. Asynchronous tasks perform micro tasks before macro tasks. And you keep doing this Loop over and over again, and that’s what we call an Event Loop.

 

Event loop is a very important and fundamental concept in JS language. We can clearly understand the execution sequence of the event cycle and the characteristics of each stage, so that we can have a clear understanding of the execution sequence of an asynchronous code, so as to reduce the uncertainty of code operation. The proper use of various methods of delaying events helps the code to better execute according to its priorities.

 

If you find some problems in this article during reading, please feel free to raise them in the comments. Thank you for reading this article.

 

The authors introduce

 

Ni Meng, web front-end development engineer of netease Yunxin, is currently engaged in the development of yunxin financial line business.