This article has participated in the third “topic writing” track of the Denver Creators Training Camp. For details, check out: Digg Project | Creators Training Camp third is ongoing, “write” to make a personal impact.


Note: Part of the article content and pictures from the network, if there is infringement please contact me (homepage public number: small siege lion learning front)

By: Little front-end siege lion, home page: little front-end siege lion home page, source: Nuggets

GitHub: P-J27, CSDN: PJ wants to be a front-end siege lion

Copyright belongs to the author. Commercial reprint please contact the author for authorization, non-commercial reprint please indicate the source.


preface

First of all, we all know that JavaScript is single threaded, so let’s say that every renderer has a main thread, and the main thread is very busy, not only dealing with the DOM, but also calculating styles, and also dealing with UI layout, and also dealing with JavaScript tasks and all kinds of input events. To keep so many different types of tasks running smoothly in the main thread, you need a system to schedule them. This brings us to EventLoop, as we all know JavaScript doesn’t have its own loop system, it relies on the browser loop system provided by the rendering process!

What is EventLoop?

So let’s take a look at this picture, regardless of what a macro task is, what a micro task is, let’s take a look at the whole process.

Analysis:

  1. Checks whether the macro task queue is empty

    • Not empty –> Execute the earliest queued task –> execute the next step
    • Empty –> Go to the next step
  2. Check whether the microtask queue is empty

    • Not empty –> Execute the first queued task –> continue to check whether the microtask queue is empty
    • Empty –> Go to the next step

The first execution of the macro queue will have script tasks, so the asynchronous task will execute all the micro tasks first after Js parsing. Note that newly created microtasks are immediately queued for execution in the microtask queue without waiting for the next reincarnation.

The main thread reads events from the task queue in a continuous Loop, so the whole operation mechanism is also called an Event Loop.

Before diving into the event loop, a few concepts need to be understood:

  • Execution Context
  • Execution Stack
  • Micro-task
  • Macro-task

Execution Context

An execution context is an abstract concept that can be understood as an environment in which code is executed. JS execution context is divided into three types: global execution context, function (local) execution context, Eval execution context.

  • Global execution contextThe: global execution context refers to the window to which the global this points. It can be an externally loaded JS file or code in a local tag.
  • Function execution context: Function context is also called local context, each function is called, a new local context is created.
  • Eval execution context: This is not commonly used and is not mentioned here.

Execution Stack

The execution stack is the “stack” in our data structure. It has the characteristic of “first in, last out”. It is because of this characteristic that when our code is executing, it encounters an execution context and pushes it into the execution stack successively.

When the code is executed, the code in the execution context at the top of the stack is executed first. When the execution context code at the top of the stack is completed, it is removed from the stack and continues to execute the next execution context at the top of the stack.

function foo() {
    console.log('a');
    bar();
    console.log('b');
}
function bar() {
    console.log('c');
}
foo();
Copy the code
  1. Initialization state, execution stack task is empty.
  2. Foo executes, foo goes to the stack, prints a, hits bar.
  3. Bar then enters the execution stack, executes bar, and prints c.
  4. The bar function exits the stack, continues to execute foo at the top of the stack, and prints b.
  5. Foo is removed from the stack, and all tasks on the stack are completed.

What are macro tasks and micro tasks?

We all know that Js is single-threaded, but some time-consuming operations can cause process blocking problems. To solve this problem, Js has two execution modes for tasks: Synchronous and Asynchronous.

In asynchronous mode, you can create asynchronous tasks into macro tasks and micro tasks. In the ES6 specification,

  • Macrotasks are called tasks, and microtasks are called Jobs.
  • Macro tasks are initiated by the host (browser, Node), while microtasks are initiated by JS itself.
Several ways to create macro tasks and micro tasks 👇
MacroTasks Microtasks
setTimeout RequestAnimationFrame (controversial)
setInterval MutationObserver (Browser environment)
MessageChannel Promise.[ then/catch/finally ]
I/O, event queue Process.nexttick (Node environment)
SetImmediate (Node environment) queueMicrotask
Script (whole block of code)

Note: nextTick queues are executed before Promie queues.

How to understand that script is a macro task 🤔

In fact, if two script blocks exist at the same time, the synchronization code in the first script block will be executed first. If a microtask is created and entered into the microtask queue during this process, after the execution of the first script synchronization code, the microtask queue will be emptied first. Start the execution of the second script block.

So this should make sense why a script is a macro task.

Now that that’s clear, how does the loop work? The sequence of tasks described below is based on the function call stack.

  1. First, the event loop mechanism is subordinatescriptThe code inside the tag starts, as we mentioned above, with the wholescriptThe tag is handled as a macro task.
  2. During code execution, if you encounter a macro task such as:setTimeout, the current task will be distributed to the corresponding execution queue.
  3. In the process of execution, if micro-tasks are encountered, such as: PromiseIn creatingPromise Instance object, the code executes sequentially, if executedThen,Action, and the task is dispatched to the microtask queue.
  4. script The code in the tag is executed, and the macro tasks and micro tasks involved in the execution process are also assigned to the corresponding queue.
  5. At this point, the macro task is completed and all existing microtasks are executed in the microtask queue.
  6. The microtask completes, the first message loop completes, and the page is rendered once.
  7. The second message loop then begins, fetching tasks from the macro task queue for execution.
  8. If the two task queues have no more tasks to execute, all tasks are completed.

The timersetTimeout

In addition to the task queue, you can also put timer callback functions, which need to specify how much time certain code execution.

Timers include two functions: setTimeout and setInterval. When we set the timer time to perform a specific task, as follows:

  // Execute after 1 second
  setTimeout(function () {
    console.log(2);
  }, 1000);
  console.log(1)
Copy the code

The above output is 1, 2. After the synchronization code is executed, the task event in the timer is executed

  // Execute the synchronization immediately
  setTimeout(function () {
    console.log(2);
  }, 0);
  console.log(1)
Copy the code

When we execute the setTimeout (fn,0) timer, we place the scheduled task callback at the end of the task queue, which implies early execution.

That is, wait until the main thread synchronized tasks and existing events in the “task queue” are processed, and then execute the timer task immediately.

The above premise is that after the code of the synchronization task and the task queue is completed, if the current code is executing for a long time, the timer does not guarantee that it will be executed at the specified time.

Note: The HTML5 standard specifies the minimum value (minimum interval) for the second parameter of setTimeout(), which must not be less than 4 milliseconds. If it is less than this value, it is automatically increased.

If changes to the page are involved, this timer task is usually not executed immediately, but every 16 milliseconds, and we usually use requestAnimationFrame().

Little practical

  console.log('1');
  setTimeout(() = > {
    console.log('2')},1000);
  new Promise((resolve, reject) = > {
    console.log('3');
    resolve();
    console.log('4');
  }).then(() = > {
    console.log('5');
  });
  console.log('6');/ / 1,3,4,6,5,2

Copy the code

Analysis:

  • Initialization state, execution stack is empty.
  • Executed first<script>Tag, at which point the global code into the execution stack, synchronous sequential code execution, output 1.
  • Asynchronous code encountered during executionSetTimeout (macro task)And assign it to the macro task asynchronous queue.
  • The synchronization code continues and one is encounteredPromise asynchronous code (microtasks). But the code in the constructor is synchronous code, output 3, 4, thenthenSubsequent tasks are added to the microtask queue.
  • Finally, the synchronization code is executed, printing 6.
  • becausescript The code in is processed as a macro task, so this loop continues to process all asynchronous tasks in the microtask queue until all tasks in the microtask queue are completed. There is only one microtask in the microtask queue, so output 5.
  • The page is rendered once and the next loop is completed.
  • Retrieves a macro task from the macro task queue, the previous one setTimeout, and finally outputs 2.
  • At this point, the task queue is empty, the execution stack is empty, and the whole program is executed.

The above is inevitably a little wordy, so simplify the following steps:

  • The macro task (synchronized code in script) is executed at first, and the call stack is empty after execution.
  • Then check if there are any executable tasks in the microtask queue and complete all the microtasks.
  • Render the page.
  • In the second round, a macro task is removed from the macro task queue and executed, and the above cycle is repeated.

Thank you for reading, I hope to help you, if there is a mistake or infringement of the article, you can leave a message in the comment area or add a public number in my home page to contact me.

Writing is not easy, if you feel good, you can “like” + “comment” thanks for your support ❤