Event Loop in browser

Concurrency model and Event Loop -MDN JavaScript

We all know that JavaScript is single-threaded, which means you can only do one thing at a time. This is because JavaScript is primarily used to manipulate the DOM, and if it becomes multithreaded, the browser will be at a loss to know who to listen to. However, although JS is a single thread, it can simulate multithreading completely, relying on the Event Loop.

We all know that the code in JS is divided into synchronous and asynchronous, the so-called asynchronous actually means that we do not block the main thread, waiting for the main thread code to complete execution before execution. callback setTimeout setInterval Promise … All of this is asynchronous code that we’re all familiar with


As shown in the figure, the memory in JS is divided into heap memory and stack memory. The heap memory stores the data of object type declared by us, and the stack memory stores the basic data type and the running space when the function is executed. Our synchronous code is on the execution stack. What about asynchronous code? The browser will queue up asynchronous code such as DOM events, Ajax setTimeout, etc., and wait for all the code in the execution stack to complete execution before executing the code in the queue. Is it similar to the publish-subscribe mode?


console.log(1);
setTimeout(() => {
    console.log(2);    
}, 0);
console.log(3);
Copy the code

According to the previous statement, setTimeout will be queued until the code in the execution stack completes, so it will print 1, 3, 2


But asynchronous code is different:

console.log(1)

setTimeout(() => {
    console.log(2)
}, 0)

Promise.resolve().then(() => {
    console.log(3)
})
Copy the code

The output is always 1, 3, 2, which means that the promise is executed before setTimeout. This is because asynchronous tasks are divided into microtasks and macro tasks, which are executed in the order of executing the code on the stack => microtasks => macro tasks.


Execution stack

  • Execution stackCode in is always executed first

Micro tasks (microtask) :promise MutationObserver...

  • whenExecution stackThe code in theMacro task queueLet’s take a look beforeMicrotask queueIs there any mission in China? If so, it will be firstMicrotask queueIs executed only after the task is clearedMacro task queue

Macro task (task) :SetTimeout setInterval setImmediate(IE only) messageChannel

  • Waiting for theExecution stackandMicrotask queueAll are executed, and each is executedMacro taskAfter that, I’ll check it outMicrotask queueIs there any new task added? If yes, will firstMicro tasksThe next task is executed only when the task in the queue is clearedMacro task

setTimeout(() => {
    console.log('timeout1')
    Promise.resolve().then(() => {
        console.log('promise1')
    })
    Promise.resolve().then(() => {
        console.log('promise2')})}, 100)setTimeout(() => {
    console.log('timeout2')
    Promise.resolve().then(() => {
        console.log('promise3')})}, 200)Copy the code
  1. The first twosetTimeoutTo the macro task queue
  2. When the firstsetTimeout1When it’s time to execute, first print timeout1 and then stuff it into the microtask queuepromise1andpromise2
  3. When the firstsetTimeout1When he’s done, he goes to the microtask queue to check if it’s empty, and he finds twopromise, will put twopromiseExecute sequentially before executing the next macro task
  4. twopromiseAfter the execution, there are no tasks in the microtask queue and the next task will be executed in the macro tasksetTimeout2
  5. whensetTimeout2To execute, a timeout2 is printed, and another is inserted into the microtask queuepromise2
  6. whensetTimeout2When the task is executed, the microtask queue is checked and a promise3 is createdpromise3perform
  7. It will print one by onetimeout1 promise1 promise2 timeout2 promise3

Event Loop in Node

Resources: Libuv Node documentation

We all know that Node.js is a JavaScript runtime environment based on the Chrome V8 engine, which allows JS to run on the server. However, the Event Loop in Node is simulated by Libuv. It allocates different tasks to different threads and forms an Event Loop, which asynchronously returns the execution results of tasks to V8 engine.


  • Microtasks in Node:process.nextTric promise setImmediate...
  • Macro tasks in Node:setTimeout setInterval...


  • Timers: Execute the callback that expires in setTimeout() and setInterval().
  • I/O Callbacks: A small number of I/ OCallbacks in the previous cycle are delayed until this stage of the cycle
  • Idle, prepare: Used internally only
  • Poll: The most important phase. Perform I/O callback to check whether timers expire timer blocks under appropriate conditions during this phase
  • Check: Performs the Callback of setImmediate
  • Close callbacks: Callback to execute a close event, such as socket.on(“close”,func)

The Event Loop in Node will clear the microtask queue every time when the queue is switched, so it will complete the execution of the current queue and check whether there is any task in the microtask when entering the next stage

setTimeout(() => {
    console.log('timeout1')
    Promise.resolve().then(() => {
        console.log('promise1')
    })
    Promise.resolve().then(() => {
        console.log('promise2')})}, 0)setTimeout(() => {
    console.log('timeout2')
    Promise.resolve().then(() => {
        console.log('promise3')})}, 0)Copy the code
  1. The first twosetTimeoutTo the macro task queue
  2. When the firstsetTimeout1When it’s time to execute, first print timeout1 and then stuff it into the microtask queuepromise1andpromise2
  3. When the firstsetTimeout1After the command is executed, proceed to the next commandsetTimeout2
  4. whensetTimeout2To execute, a timeout2 is printed, and another is inserted into the microtask queuepromise2
  5. The current macro task queue is empty, and the next step is to check whether there are any tasks in the micro task queue
  6. Clear the microtask queue
  7. Execution in the Node environment prints sequentiallytimeout1 timeout2 promise1 promise2 promise3