When we write javascript code that is loaded through the browser to the rendered page and then to the page interaction, it is important for us to know who comes first and who comes last in our code. This part of the knowledge involves the browser’s event loop
1. Processes and threads
- Processes: In this way, we can think of the computer running programs, projects and applications as a process, running the application we are enabled. When the application shuts down, it also means that the process exits from our computer. In an obvious way, each entry in our task manager/activity monitor is a process.
- Thread: contains threads in a process at least one or more threads in a process, thread is the smallest unit of computer call.
- When we open a browser page card, we have a process, and these processes contain many threads:
- Js engine threads that parse and execute JS code are also called master threads
- Events trigger thread events trigger Dom events publish subscribe events JS callbacks and so on
- Timer trigger thread specifically handles timer trigger timer reclaim
- Asynchronous Http request threads that process Http requests in resources
- GUI rendering will render the page resources after the resource request arrives, and the backflow and redrawing of the Dom rendered by CSS merging Dom trees will occur
- These threads work together to render the page display and interaction of our browsers
2. Asynchronous and synchronous
- Synchronization: Code is executed from top to bottom. The code below is not executed until the top is executed
- Asynchrony: Asynchrony is relative to synchronization. The above code does not block during execution.
- For example, in the browser rendering process, the JS main thread execution stack will execute synchronous code and asynchronous code. Synchronous code starts to execute in order of self-injury. When encountering asynchronous code, the current main thread will suspend another thread. . Timer webAPI will store the current timer function in the red-black tree in memory when triggering the wait event. When the timer time is up, it will be pushed into the current main thread execution stack to start executing the code in the timer.
- In the execution of the current task If the current execution stack of synchronized code block, then the subsequent asynchronous execution of code will not be executed Unless to wait for the current synchronization tasks to complete Will be in accordance with the order of the original asynchronous task to join the queue to begin an asynchronous task, until after the asynchronous task execution, event loop is performed.
// The synchronization code does not finish executing. Asynchronous code is not executed setTimeout(() = > { // Asynchronous code will not be executed because of an infinite loop document.body.style.background = 'red' }, 0); while(true) {}Copy the code
Macro and micro tasks
- Macro tasks are provided by the host environment
- Microtasks are provided by the language itself
- The task waiting to be added to the execution stack mentioned in the previous section is actually a macro task. Logical execution for asynchronous callbacks.
Then () MutationObserver queueMicrotask node process.nexttick () 2. Common macro tasks: events HTTP request timer UI render setImmidiate requestAnimationFrame etcCopy the code
Event loop call stack diagram
-
- Event loops and event loop multiple columns are maintained by event threads, which execute macro task code each time in the execution stack.
-
- The current macro task code executes the micro task and the macro task, and is added to the end of the macro task and the micro task queue respectively. After the synchronization code in the current macro task is executed, the micro task queue will be emptied first.
-
- After rendering the GUI page, the macro task to be executed will be taken out of the macro task and pressed into the execution stack to continue the current macro task operation
Frequently seen exam
document.body.style.background = 'red'
console.log(1)
Promise.resolve().then(() = > {
console.log(2)
document.body.style.background = 'yellow'
})
console.log(3) Yellow or the transition from red to yellowCopy the code
- The display is always yellow: the microtask code is executed before the GUI renders. Event ring call stack diagram visible
btn.addEventListener('click'.function() {
console.log('listener1')
Promise.resolve().then(() = >{
console.log('micro task1')
})
})
btn.addEventListener('click'.function() {
console.log('listener2')
Promise.resolve().then(() = >{
console.log('micro task2')
})
})
btn.click()
Copy the code
- Listener1 Listener2 Micro Task1 Micro Task2 when the js call stack is executed, the JS thread will execute the addEventListener concurrently
- When we annotate the btn.click() button to trigger the macro task involved in the event loop queue due to the browser click event, the output is Listener1 Micro Task1 Listener2 Micro Task2
console.log(1)
async function async1() {
console.log(2)
await console.log(3)
console.log(4)}setTimeout(() = > {
console.log(5)},0);
const promise = new Promise((resolve) = > {
console.log(6)
resolve(7)
})
promise.then(res= > {
console.log(res)
})
async1()
console.log(8)
Copy the code
- The subsequent execution of the await can be regarded as time
Promise.resolve()
The subsequent execution logic of the wrapped, await statement is placed in the then microtask in the Promise. - so
await console.log(3)
The equivalent ofPromise.resolve(console.log(3)).then(() =>{})
In the operation.console.log
The function is executed immediately. - Output result:
One six, two, three, eight, seven, four, five