What is the

Javascript is a single-threaded programming language, which means that only one JS task is executing at any one time. For some tasks that require a long wait time, they will occupy the thread, causing subsequent code to fail to execute and the program to fail to work properly. This is the drawback of single thread, and JS uses the Event Loop mechanism to solve this drawback.

If you want to explain the cycle of events, you need to start with the following aspects:

  1. Stack, heap, queue
  2. Synchronization task
  3. Asynchronous tasks
  4. Asynchronous task – Macro task queue
  5. Asynchronous task – Microtask queue
  6. Event loop
  7. Event loop – Understand by example
  8. conclusion

Stack, heap, queue

The stack

A special data structure in which elements in a stack can only be accessed through one end, called the top of the stack.

  1. The data structure of the stack is last-in-first-out.
  2. All elements not at the top of the stack are inaccessible
  3. If you want the data at the bottom of the stack, you have to get rid of the elements at the top
  4. Example: like a clip, the bullet is pressed into the clip first and then discharged last

The heap

A sorted tree data structure

  1. Each node has a value.
  2. Usually when we talk about the data structure of the heap, we refer to the binary heap.
  3. A heap is characterized by the minimum (or maximum) value of the root node, and the two subtrees of the root node are also the same heap.
  4. Because of this nature of the heap, priority queues are often implemented
  5. For example: we take books from the shelf of the library. Although the books are placed in order, we don’t need to take out all the books in front of us like a stack when we want to take any book. We only need to care about the name of the book.

The queue

A special data structure in which the elements of a queue are accessed only through one end.

  1. The data structure of the queue is first-in-first-out.
  2. Adds an element to the end of the queue
  3. The top of the queue removes the element
  4. Example: like the supermarket queue settlement, the first queue of people settlement must go first

Synchronization task

When a synchronous task, which is the main thread task, starts executing javascript code, it determines whether the code is a synchronous or asynchronous task.

  1. Synchronous tasks, directly into the main thread, are executed in the order of the call stack
  2. After all synchronization tasks are executed, callback in the task queue is read

Asynchronous tasks

Asynchronous tasks are queue tasks, not main thread tasks. When the task queue notifies the main thread that an asynchronous task has a result and can be executed immediately. The task is executed on the main thread.

When an asynchronous task enters a so-called “task queue”, the task queue has the nature of a queue. First in, first out, that is, the task added later must wait for the previous task to complete before it can be executed.

If important data needs to be retrieved or an event needs to be processed during execution, it cannot be processed in a timely manner according to the first-in, first-out order of the queue.

This is where macro tasks and microtasks come in, and microtasks allow asynchronous tasks to be processed in a timely manner.

For example: macro and micro task image is: you go to business hall to handle a business will have a line number, when called to do top-up your number when you go to window business tasks performed (macro), when you deal with top-up and you want to change a package (task), staff will directly help you to do at this time, won’t make you the end of the line.

Asynchronous task – Macro task queue

  1. The macro task enters the macro task queue
  2. The event callback is a macro task
  3. Common macro tasks include Script (overall code) setTimeout setInterval I/O operations UI rendering setImmediate (node.js environment).

Asynchronous task – Microtask queue

  1. The microtask enters the microtask queue
  2. Executes after the current macro task and before the next macro task
  3. Common microtasks are promise.then Mutation Observer API process.nexttick (unique to Node)

Event loop

Some of the concepts involved in event loops are described above, but if you want to understand event loops, you also need to understand the concept of an execution stack.

Execution stack

  1. All synchronization tasks are executed on the main thread, forming an initial execution stack.
  2. In addition to the main thread, there is a “task queue”, which stores the callback function after the asynchronous task has run, and places an event in the “task queue”.
  3. Once all the synchronization tasks in the execution stack are completed, the main thread reads the task queue to see what events are in it. Then push those corresponding asynchronous tasks onto the execution stack and start executing.
  4. Each Event Loop performs all macro tasks before performing microtasks. Browser apis such as setTimeout or Ajax will be performed on other threads, and when completed, the callback task will be inserted into the Event Loop call stack, and the next time the Event Loop is executed, the operation will be performed.
  5. Select the first macro task to be queued for execution (starting with script overall code)
  6. Check whether there are microtasks. If there are, execute all tasks in the microtask queue until the microtask queue is empty
  7. Repeat the above steps

Event loop: The main thread reads asynchronous task execution from the task queue and repeats the process continuously, which is called an event loop.

Event loop – Understand by example

console.log(1); / / the main - 0
setTimeout(function () {
  console.log(2); // macro task -1
  new Promise(function (resolve) {
    console.log(3); // Microtask-2
    resolve(4);
  }).then(function (num) {
    console.log(num); // Microtask-3
  });
}, 300);

new Promise(function (resolve) {
  console.log(5); // Microtask-1
  resolve(6);
}).then(function (num) {
  console.log(num); // Microtask-1
});

setTimeout(function () {
  console.log(7); // macro task-2
}, 400);

// Output 1 5 6 2 3 4 7
Copy the code
// Microtask-2
var p = new Promise((resolve, reject) = > {
  console.log("Promise-initialization");
  resolve("Promise - results");
});

function fn1() {
  console.log("Fn1 - Execution");
}

function fn2() {
  console.log("Fn2 - Commence operation");
  setTimeout(() = > {
    console.log("SetTimeout - Execute");
  });
  fn1();
  console.log("Fn2 - Run again");
  p.then((res) = > {
    console.log("Promise - first then:" + res);
  }).then(() = > {
    console.log("Promise - The second then");
  });
}

fn2();

/ / output
("Promise-initialization");
("Fn2 - Commence operation");
("Fn1 - Execution");
("Fn2 - Run again");
("Promise - the first then.");
("Promise - The second then");
("SetTimeout - Execute");
Copy the code
var p = new Promise((resolve, reject) = > {
  console.log("Promise-initialization");
  resolve("Promise - results");
});
function fn1() {
  console.log("Fn1 - Execution");
}

function fn2() {
  console.log("Fn2 - Commence operation");
  setTimeout(() = > {
    console.log("SetTimeout - Execute");
    // start
    setTimeout(() = > {
      console.log("Another macro task.");
    });
    p.then(() = > {
      console.log("Promise - The third then");
    });
    // end
  });
  fn1();
  console.log("Fn2 - Run again");
  p.then((res) = > {
    console.log("Promise - first then:" + res);
  }).then(() = > {
    console.log("Promise - The second then");
  });
}

fn2();

/ / execution
("Promise-initialization");
("Fn2 - Commence operation");
("Fn1 - Execution");
("Fn2 - Run again");
("Promise - first then:");
("Promise - The second then");
("SetTimeout - Execute");
("Promise - The third then");
("Another macro task.");
Copy the code
  1. More and more

conclusion

JS itself is not slow, but is slow in reading and writing external data, such as waiting for Ajax requests to return results. If you wait for the Ajax result to come back and then proceed, it can take a long time. So JS designed a mechanism, CPU can ignore the IO operation, but suspend the task, execute the next task first, wait until the IO operation returns the result, then continue to execute the suspended task.

After the synchronous task is finished, the engine checks again and again to see if the pending asynchronous task meets the criteria to enter the main thread. This loop checking mechanism is called the event loop mechanism.

When the JS engine runs, in addition to a running main thread, it also provides one or more task queues containing various pending asynchronous tasks. First, the main thread will execute all synchronous tasks, and when all synchronous tasks are finished, it will look at the asynchronous tasks in the task queue. If the conditions are met, the asynchronous task will re-enter the main thread and start executing, and then it will become a synchronous task. The next asynchronous task enters the main thread to start execution. Once the task queue is empty, the program ends execution.