1. What is an Event Loop
Js is single threaded. When a program is running, only one thread exists to do one thing at a time. Single threading means that all tasks need to be queued until the first one is finished before the next one can be executed. If the first task takes a long time, the second task has to wait forever.
The reason for this design depends on the context in which JavaScript is used.
At the beginning, JavaScript, as a browser scripting language, is usually used to manipulate THE DOM. If it is multi-threaded, one thread deletes the DOM and another adds the DOM, how should the browser handle this situation?
- All synchronization tasks are executed on the main thread, forming an execution stack
- In addition to the main thread, there is a “task queue”. The asynchronous task enters the task queue. Procedure
- 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.
Whenever the main thread is empty, it reads the “task queue”, that’s how JavaScript works. The process repeats itself. This mechanism is called an Event Loop.
2. Task queue
All tasks can be categorized into two types, 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. For example, Ajax web requests and setTimeout timing functions are asynchronous tasks.
3. Macro and micro tasks
Micro tasks
A function that needs to be executed asynchronously, after the execution of the main function and before the completion of the current macro task
Common microtasks include:
- Promise.then()
- Process. NextTick (Node. Js)
Macro task
The time granularity of macro tasks is relatively large, and the time interval of execution cannot be precisely controlled, which does not meet the requirements of high real-time performance
Common macro tasks are:
- setTimeout/setInterval
- SetImmediate, I/O Events (Node.js)
At this point, the relationship between event loops, macro tasks, and micro tasks is shown in the figure below
According to this process, its execution mechanism is:
- Execute a macro task, and if it encounters a microtask, place it in the event queue of the microtask
- After the current macro task is executed, the event queue of the microtask is viewed and all the microtasks in it are executed in sequence
Look at the following questions
console.log(1) // Print 1 for the first step
setTimeout(() = >{ // The second step timer belongs to the macro task and wait for the current macro task to execute
console.log(2) // Enable the next macro task to print 2
}, 0)
new Promise((resolve, reject) = >{
console.log('new Promise') // 第三步打印 'new Promise'
resolve()
}).then(() = >{
console.log('then') // Step 4. Then: The microtask is not executed before the current macro task is executed
// Step 6 return to the microtask print then
})
console.log(3) // First in, first out (fifO);
Copy the code
4. The async and await
‘async’ means’ async ‘and’ await ‘means’ waiting’
“Async” is used to declare an asynchronous method and “await” is used to wait for an asynchronous method to execute
async function fn1 (){
console.log(1)
await fn2()
console.log(2) / / blocking
}
async function fn2 (){
console.log('fn2')
}
fn1()
console.log(3)
Copy the code
In the example above, await will block the following code (i.e. join microtask queue), execute the synchronous code outside async, finish the synchronous code, return to async function, and execute the blocked code.
The output sequence is as follows: 1 => fn2 => 3 => 2
With that in mind, let’s try the following problem
// The program is executed from the top down
async function async1() {
console.log('async1 start') // Print async1 start
await async2() // Step 5 executes async2
console.log('async1 end')}async function async2() {
console.log('async2') // Step 6 prints async2
}
console.log('script start') // Print scriipt start
setTimeout(function () { // Move the second step to the next macro task
console.log('settimeout') // Print settimeout
})
async1() // The third step is async1
new Promise(function (resolve) {
console.log('promise1') // Step 7 Print promise1
resolve()
}).then(function () {
console.log('promise2') // Step 8 is placed in the microtask queue for execution
// Print the promise2 microtask in step 10
// Perform the next macro task, setTimeout
})
console.log('script end') // Print script end to find the current microtask
Copy the code
So the printing process is: cript start, Async1 start, AsynC2, promise1, Script end, AsynC1 end, promise2, setTimeout