Event Loop

Why is JavaScript single threaded? JavaScript engine threads

Related to its purpose. As a browser scripting language, JavaScript’s main purpose is to interact with users and manipulate DOM. This determines that it can only be single threaded, otherwise it will bring complex synchronization problems. For example, if JavaScript has two threads at the same time, one thread adds content to a DOM node and the other thread deletes that node, which thread should the browser use as the primary thread?

In order to utilize the computing power of multi-core CPUs, HTML5 proposes the Web Worker standard, which allows JavaScript scripts to create multiple threads, but the sub threads are completely controlled by the main thread and cannot operate the DOM. So, this new standard has not changed the essence of JavaScript single threading.

Task queue

Background: Single threading means that all tasks need to be queued until the previous task is completed before the next task can be executed. If queuing is due to high computational load and the CPU is too busy, then it’s okay. However, many times the CPU is idle because IO devices (input and output devices) are slow (such as Ajax operations reading data from the network) and have to wait for the results to come out before proceeding. The designers of the JavaScript language realized that at this point, the main thread could completely ignore the IO device, suspend the waiting tasks, and run the later tasks first. Wait until the IO device returns the result, then turn back and continue executing the suspended task.

Synchronous tasks and asynchronous tasks: All tasks can be divided into two types: synchronous tasks and asynchronous tasks. Synchronous tasks refer to tasks that are queued for execution on the main thread. Only after the previous task is completed can the next task be executed; Asynchronous tasks refer to tasks that do not enter the main thread but instead enter the task queue. Only when the task queue notifies the main thread that an asynchronous task can be executed, will the task enter the main thread for execution.

Asynchronous operation mechanism:

All synchronization tasks are executed on the main thread, forming an execution context stack.

In addition to the main thread, there is also a task queue. As long as the asynchronous task has a running result, place an event in the “task queue”.

Once all synchronization tasks in the “execution stack” are completed, the system will read the “task queue” to see which events are inside. The corresponding asynchronous tasks end the waiting state, enter the execution stack, and begin execution.

The main thread repeatedly repeats the third step above.

Events and callback functions

“Task queue” is a queue of events (also understood as a queue of messages). When an IO device completes a task, it adds an event to the “task queue” to indicate that the relevant asynchronous task can enter the “execution stack”. The main thread reads the “task queue”, which is to read which events are inside.

The events in the task queue, in addition to IO device events, also include some user generated events (such as mouse clicks, page scrolling, etc.). As long as a callback function is specified, these events will enter the “task queue” and wait for the main thread to read.

The so-called “callback function” refers to the code that will be hung by the main thread. Asynchronous tasks must specify a callback function, and when the main thread starts executing the asynchronous task, the corresponding callback function is executed.

“Task queue” is a first in, first out data structure, where the events that rank first are read first by the main thread. The reading process of the main thread is basically automatic. As soon as the stack is cleared, the first event on the “task queue” automatically enters the main thread. However, due to the existence of the “timer” function mentioned later, the main thread first needs to check the execution time, and certain events can only return to the main thread after reaching the specified time.

Event Loop

Definition: The main thread reads events from the “task queue”, and this process is a continuous loop, so the entire running mechanism is also called an Event Loop.

When the main thread runs, it generates a heap and a stack. The code in the stack calls various external APIs, which add various events (click, load, do) to the “task queue”. As long as the code in the stack is executed, the main thread will read the “task queue” and sequentially execute the callback functions corresponding to those events.


In addition to events that place asynchronous tasks, “task queues” can also place scheduled events, which specify how long certain code will be executed. This is called the “timer” function, which is the code that is executed at a fixed time.

In summary, the meaning of setTimeout (fn, 0) is to specify that a task is executed at the earliest available idle time of the main thread, that is, as early as possible. It adds an event at the end of the “task queue”, so it will not be executed until both the synchronization task and the existing events in the “task queue” are processed.