How does js execute in a single thread

As far as everyone knows, js is executed in a single thread. Then you will come into contact with threads and processes, synchronous execution and asynchronous execution, and the concept of js single-threaded execution principles.

1. The concept of process and thread

1.1 Process

A process is the basic unit for resource allocation by the CPU. The browser uses multiple processes, and a tab corresponds to a process. This process is responsible for managing the creation and destruction of each tab, forward and backward, and other operations.

1.2 Threads

Thread is the smallest unit of CPU scheduling. Multiple threads can correspond to a single process, and they can share the memory size of the process.

2. How does js single thread realize synchronous and asynchronous

2.1 Why js is single-threaded

If js is multi-threaded, there will be thread conflicts at the same time.
For example, the first thread adds content to node A of the DOM, and the second thread deletes this node A, so which process is the main one in the end?
So js uses a single thread, and only one synchronous task will be executed at a time. But it does not mean that there is only one thread in the js engine, it just means that only one thread (usually called the main thread) is used to execute js code, and other threads are used for background processing.

2.2 js executes synchronous tasks

2.2.1 The principle of js to execute synchronous tasks

js is single-threaded, which means that only one task can be executed at the same time, and the remaining tasks need to wait later. When the previous tasks are completed, the subsequent tasks are executed.

2.2.2 The relationship between js execution synchronization tasks and the stack

When js performs synchronization tasks, the data structure chosen is the stack, which maintains the concept of first-in-last-out and order.
For example, when executing a task function A will call function B, then the stack frame of function B will become the current frame, and the stack frame of function A will become the calling frame. When function B finishes executing, it calls back to function A and continues to execute A.

2.3 js executes asynchronous tasks

2.3.1 The principle of js executing asynchronous tasks

When JS encounters an asynchronously executed task, it will put it in the task queue first, and will not process the asynchronous task for the time being, but will continue to execute the synchronous task, so that the JS single-threaded task will not be blocked.
When the js single thread is idle and the asynchronous task notification in the task queue can be executed, the asynchronous task will be taken out of the task queue and put on the thread for execution.

2.3.2 What is a task queue

The task queue is used to store the asynchronous tasks encountered by js single thread. There are multiple task queues.

2.3.3 The relationship between js execution of asynchronous tasks and queues

We know that the task queue is based on the data structure of the queue, maintaining the concept of first-in first-out and order.
That is to say, when the js single-threaded execution stack is empty, it will be taken out of the task queue and executed sequentially (if the task queue is notified that the asynchronous tasks in the queue can be executed)

2.3.4 How the task queue is used

In the form of a callback function, the execution stack is notified that it can be executed.
Basically, in the following situations, the above tasks will be divided according to certain rules through Web APIs. Macro events will be placed in macro queues, and micro events will be placed in micro queues (this concept will be described in 2.3.5), for example:

  1. The DOM Binding module handles some onclick functions
  2. The network module handles ajax requests
  3. Use timer setTimeout
  4. use promises

In order to be able to check in real time whether the task queue can be called back to run in the main thread, the event loop Event Loop is used.
It is to create a loop process similar to while(true), and the loop process becomes Tick. The single thread of JS loops over and over again to check whether there are asynchronous tasks to be executed in the task queue, and if so, take out the relevant event and put it into the execution stack of the single thread through the callback function.

2.3.5 Macro task and micro task of task queue

2.3.5.1 What are macro tasks and micro tasks

  • Macro tasks: global synchronization code in js, setTimeout management module, AJAX request management module, Dom event management module, etc.
  • Micro task: Promise management module, mutation management module

2.3.5.2 Execution principles of macro-tasks and micro-tasks

After all the synchronization tasks are executed and the execution stack is empty (the synchronization task is equivalent to the execution of the first macro task), every time the macro task is executed, it will first check whether there are tasks in the micro queue. If there is, execute all of them before executing the second macro task; if not, execute the second macro task directly. and so on.

2.3.5.3 Execution code understanding and animation of macro-tasks and micro-tasks

console.log('start')
setTimeout(function() {
    
    
  console.log('setTimeout')
}, 0)

Promise.resolve().then(function() {
    
    
  console.log('promise1')
}).then(function() {
    
    
  console.log('promise2')
})

console.log('end')

The specific code execution stack and corresponding task queue operations are as follows:
insert image description here

As can be seen from the above code and animation diagram, it is executed sequentially from top to bottom.
We first divide it into two parts: synchronous task and asynchronous task:
1. Synchronous execution
1. Encountering console.log('start') is a synchronous task and is executed directly.
2. If the setTimeout code block is a macro task in the asynchronous task, put it into the macro queue macrotask in the task queue and suspend it.
3. When the Promise code block is a microtask in the asynchronous task, put it into the microtask in the task queue and suspend it.
4. Encountering console.log('end') is a synchronous task, which is executed directly. So far, all synchronous tasks have been executed.

2. Asynchronous execution
1. After the synchronous task is completed, the global code belongs to the macrotask macrotask. After the macrotask is executed, it starts to check whether the microqueue in the task queue is executed.
2. Call back the Promise code block of the microtask, put it into the execution stack for execution, and execute the console.log('promise1') in it.
3. The callback function of the Promise code block of the microtask returns undefined. Then, the state of primose will change from pending to fulfilled, and continue to be put into the microtask microqueue.
4. Enter the event loop event loop, execute the .then() callback at this time to execute console.log('promise2'), and the microtask queue of the asynchronous task is completed.
5. Enter the event loop event loop again, and execute the macro task in the asynchronous task (at this time, the micro task does not need to be executed, so the next macro task is directly executed). Execute setTimeout(), after a delay of 0, console.log('setTimeout').
6. So far, all the task queues have been executed, and the event loop is still waiting for a new round of code to be processed.

2.3.6 async-await in asynchronous tasks

The execution order of threads will also be affected by async-await, promise, and setTimeOut. Now the main focus is on async-await.

2.3.6.1 What is async-await?

async is a function and returns a Promise object, used with await. When await is encountered in the async function, await is like the operation of giving up the thread. When the content on the right is completed, the thread is given up, and the rest of the async code is suspended, and it is executed after the remaining synchronization tasks are completed.

2.3.6.1 async-await, promise, setTimeOut code running

	async function async1(){
    
    
	  console.log('async1 start')
	  await async2()
	  console.log('async1 end')
	}
	async function async2(){
    
    
	  console.log('async2')
	}
	console.log('script start')
	setTimeout(function(){
    
    
	  console.log('setTimeout')
	},0)
	async1();
	new Promise(function(resolve){
    
    
	  console.log('promise1')
	  resolve();
	}).then(function(){
    
    
	  console.log('promise2')
	})
	console.log('script end') 

After running the code is printed as
script start
async1 start
async2
promise1
script end
async1 end
promise2
setTimeout

It can be seen that function async2() returns a Promise, await async2() is equivalent to function async2(), and then() returns the value it will return after successful execution. At this time, awiat will give up the thread, jump out of the asynchronous execution of function async1(), and continue to execute the following synchronization tasks. After all the synchronization tasks are executed, then execute the rest of function async1().

Guess you like

Origin blog.csdn.net/Ak47a7/article/details/130033501