1. Why is JavaScript single threaded?

One of the hallmarks of the JavaScript language is single-threaded, which means you can only do one thing at a time. So why can’t JavaScript have multiple threads? It’s more efficient. The single thread of JavaScript, relative to its purpose. As a browser scripting language, JavaScript’s primary purpose is to interact with users and manipulate the DOM. This means that it has to be single-threaded, which can cause complex synchronization problems. For example, if there are two threads of JavaScript at the same time, one thread adds content to a DOM node, and the other thread removes that node, which thread should the browser use?

So, to avoid complexity, JavaScript has been single-threaded since its inception, and this has been a core feature of the language and will not change.

In order to make use of the computing power of multi-core CPU, HTML5 proposes the Web Worker standard, which allows JavaScript scripts to create multiple threads, but the child threads are completely controlled by the main thread and cannot operate DOM. So, this new standard doesn’t change the single-threaded nature of JavaScript.

2. Knowledge points related to execution mechanism

2.1 Synchronous and Asynchronous Tasks

  • Synchronization task
  • Asynchronous tasks

One day, Zhang SAN has to cook a meal. At this time, he has to do two things: steamed rice and copied vegetables. Now there are two ways to complete this task

A. Steam the rice first and wait until the rice is ready to copy the dishes — synchronous tasks

B. Steam the rice first and then copy the dishes while the rice is being steamed — asynchronous task

The two modes are synchronous and asynchronous. A synchronization task refers to a task that is queued to be executed on the main thread. The next task can be executed only after the first task is completed. Asynchronous tasks are tasks that do not enter the main thread but enter the task queue. The task queue notifies the main thread that an asynchronous task is ready to execute.

When we open a website, the rendering process of the page is a lot of synchronization tasks, such as rendering the page skeleton and page elements. Tasks that take a lot of time, like loading pictures and music, are asynchronous tasks. , we use the map to illustrate:

In particular, asynchronous execution works as follows. (The same is true for synchronous execution, since it can be considered asynchronous execution without asynchronous tasks.)

(1) All synchronization tasks are executed on the main thread, forming an execution context stack. (2) In addition to the main thread, there is a task queue. Whenever an asynchronous task has a result, an event is placed in the “task queue”. (3) Once all synchronization tasks in the “execution stack” are completed, the system reads the “task queue” to see what events are in it. Those corresponding asynchronous tasks then end the wait state, enter the execution stack, and start executing. (4) The main thread repeats step 3 above.

2.3 macro and micro tasks in JavaScript

In addition to the broad definition, we can further define tasks into macro tasks and micro tasks:

  • Macro-task: includes the execution of the overall code script, setTimeout, setInterval, Ajax, DOM operations, such as I/O operations, UI rendering, etc

  • Micro-task: Promise calls back to Process. nextTick in Node, a MutationObserver that listens for Dom changes.

The main thread reads events from the “task queue”. This process is repeated, so the whole operation mechanism is also called the Event Loop.

Let’s explain this graph:

  • Synchronous and asynchronous tasks enter different execution “places”, synchronous to the main thread, asynchronous to the main threadEvent TableAnd register the function.
  • When the assigned task is complete,Event TableI’m going to move this function inEvent Queue.
  • Tasks in the main thread are empty and goEvent QueueRead the corresponding function, into the main thread execution.
  • The above process is repeated over and over again, as is often said**Event Loop**(Event loop). (Event Loop is javascript’s execution mechanism)

3, summarize

3.1 Interview Answer

What should you say in an interview? Here are my recommended answers:

  1. First of all, JS runs in a single thread. When the code is executed, the execution context of different functions is pushed into the execution stack to ensure the orderly execution of the code.
  2. If an asynchronous event is encountered while executing synchronous code, the JS engine does not wait for the result to return. Instead, it suspends the event and continues executing other tasks in the execution stack
  3. When the synchronous event is complete, the callback corresponding to the asynchronous event is added to a different task queue from the current stack for execution.
  4. Task queue can be divided into macro task pair column and micro task pair column. When the execution of events in the current execution stack is completed, JS engine will first judge whether there are tasks in the micro task pair column that can be executed. If there are, the event at the top of the micro task queue will be pushed into the stack for execution.
  5. When the tasks in the microtask pair column are completed, the tasks in the macro task pair column are judged.

3.2 priority

3.2.1 setTimeout (), setInterval ()

SetTimeout () and setInterval() work exactly the same internally, except that the former specifies code to execute once, while the latter executes repeatedly.

SetTimeout () and setInterval() generate asynchronous and macro tasks.

SetTimeout () takes two arguments, the first being the callback function and the second the number of milliseconds to delay execution. SetInterval () takes two arguments, the first a callback function and the second the number of milliseconds to execute repeatedly.

If the second parameter is set to 0 or not, it does not mean to execute immediately, but rather to specify that a task should be executed at the earliest available free time on the main thread, that is, as early as possible. It adds an event to the end of the “task queue”, so it does not execute until both the synchronized task and the existing events in the “task queue” are processed.

Therefore, setTimeout() and setInterval() are not absolute. They need to be determined according to the final execution time of the current code. To put it simply, If the current code execution time (such as execution of 200ms) exceeds the delay (setTimeout(fn, 100)) or repeated execution (setInterval(fn, 100)), There is no difference between setTimeout(fn, 100) and setTimeout(fn, 0), and there is no difference between setInterval(fn, 100) and setInterval(fn, 0).

3.2.2 Promise

Promises are relatively special. The callback passed in new Promise() is executed immediately, but its then() method is executed after the execution stack and before the task queue, which is a microtask.

3.2.3 process. NextTick

Process.nexttick is a “task queue” method provided by Node.js. It produces tasks at the end of the execution stack, not macro or micro tasks, so its tasks always occur before all asynchronous tasks.

3.2.4 setImmediate

SetImmediate setImmediate is another “task queue” method provided by Node.js. It generates tasks that append to the end of the “task queue”. It is similar to setTimeout(fn, 0), but setTimeout takes precedence over setImmediate.

Sometimes setTimeout is executed before setImmediate, and sometimes after setImmediate. This is not a Node.js bug, because while setTimeout’s second parameter is set to 0 or none, However, setTimeout source code will specify a specific number of milliseconds (node is 1ms, browser is 4ms), and the current code execution time is affected by the execution environment, the execution time fluctuates, if the current code execution is less than the specified value, setTimeout has not reached the time to postpone execution. SetImmediate naturally executes first, and setTimeout precedes setImmediate if the code currently executing exceeds the specified value.

3.2.5 Summarizing Priorities Key Points Key Points Key Points Key Points

From the above, we can derive a code execution priority:

Synchronizing code (macro task) > process.nextTick > Promise (microtask) > setTimeout(fn), setInterval(FN) > setImmediate (macro task) > setTimeout(fn, Time) and setInterval(fn, time), where time>0

4. Test your learning with examples

The first question:

SetTimeout (function() {console.log(1) {console.log(1)}, 0); new Promise(function(resolve, reject) { console.log(2); Resolve ()}).then(function() {console.log(3)}); //// The following code is required to execute process.nexttick (function () {console.log(4) // Put the task on queue temporarily}) console.log(5) // output 5Copy the code

What is the meaning of the passage?

Round 1: setTimeout is a macro task, which is not executed and placed in the task queue

Execute the new Promise output 2 then callback function as a micro task, temporarily put into the task queue

NextTick also throws the callback function to the task queue, and continues execution, printing 5

Until this synchronization task is complete, proceed with the priority given earlier

Process. NextTick output 4

Find microtasks in the task queue find then callback function output 3 microtasks completed

Find macro task setTimeout output 1

Results: 25431Copy the code

The second question

console.log(1); SetTimeout (function () {console.log(2); New Promise(function (resolve, reject) {console.log(3); resolve(); console.log(4); }).then(function () { console.log(5); }); }); function fn() { console.log(6); SetTimeout (function () {console.log(7); }, 50); } new Promise(function (resolve, reject) { console.log(8); resolve(); console.log(9); }). Then (function () {console.log(10); }); fn(); console.log(11); NextTick (function () {console.log(12); // The following code needs to execute process.nexttick (function () {console.log(12); }); setImmediate(function () { console.log(13); });Copy the code

The output is 1, 8, 9, 6, 11, 12

Running microtasks:

new Promise(function (resolve, reject) { // console.log(8); // resolve(); // console.log(9); }).then(function () {console.log(10); });Copy the code

The output is: 10

Read the callback function of “task queue” into “execution stack” :

setTimeout(function () { console.log(2); new Promise(function (resolve, reject) { console.log(3); resolve(); console.log(4); }) //.then(function () {// console.log(5); / /}); });Copy the code

The output is: 2, 3, and 4

Run the microtask again:

setTimeout(function () { // console.log(2); New Promise(function (resolve, reject) {// console.log(3); // resolve(); // console.log(4); }).then(function () {console.log(5); }); });Copy the code

The output is: 5

Then read the callback function of “task queue” into “execution stack” :

setImmediate(function () {
Copy the code

The output is 13

Running microtasks:

There is no

Then read the callback function of “task queue” into “execution stack” :

// function fn() {// done // console.log(6); // setTimeout(function () {console.log(7); }, 50); / /}Copy the code

The output is: 7

Running microtasks:

There is no

To sum up, the final output sequence is: 1 8 9 6 11 12 10 2 3 4 5 13 7

Those of you who have seen this should already be familiar with JavaScript execution

I hope you all come true in 2021

I am a front magician a white welcome to like thank you

Refer to the link



Juejin. Cn/post / 684490…


Juejin. Cn/post / 684490…