Browser event loop
- Process: The smallest unit of a computer that assigns and schedules tasks. The browser is a multi-process model
- Thread: A unit of a process
- What threads does the entire browser use to render a web page?
- First, each page card has a rendering process (browser kernel)
- The renderer process contains the following threads:
- GUI rendering thread page rendering drawing draws 3D animation
- The rendering thread suspends mutex when the JS engine executes JS code
- The event triggers the thread eventloop
- Webapi also creates threads, and events/timers/Ajax requests create separate threads
- When I say js is single threaded I mean the main thread is single threaded
EventLoop
- Js execution may call asynchronous methods. How do these methods schedule execution
- It is scanned repeatedly by a separate thread
- Js will be executed from top to bottom. When a function is encountered, the execution context will be created and put into the execution stack. After execution, the stack will be removed.
- When the execution context stack is complete, the callback function is placed on the event queue when the API execution is complete or the time is up.
- A separate thread continuously scans the queue, pulling tasks out of the queue and putting them on the context stack to execute the event loop thread is specifically designed to do this, detect whether the stack is empty, and if so, pull one out of the event queue to execute (e.g., the setTimeout macro task).
- There are also some tasks that happen when the code executes, the promise for example, the micro task, and each time you execute a macro task, you create a separate queue of micro tasks first in first out
- The browser detects whether to re-render the browser after the microtask has been executed with a refresh rate of about 16.6ms
- Each loop executes one macro task at a time and emptying the corresponding microtask queue. At the end of each loop, it is determined whether to render or not, and only render if necessary
- Summary: Js code is executed, it is a macro task, after the execution will put this task to empty, empty may occur after a page rendering (pages may render may not rendering), after see macro task, to have any task from macro to remove one by execution, execution time may cause a small task, and may cause the macro and task, There is only one macro task queue, and there will be a new one for each round of the micro task queue. Each macro task has its own micro task queue, and then empty it, and then see if it needs to render, and then take a macro task… That’s what eventLoop does
- SetTimeout setInterval postMessage MessageChannel setImmediste is also a macro task event ajax
- Microtask promise.then mutationObserver
- Microtasks generated during execution in microtasks will be cleared directly in this round
- Macro tasks generated in microtasks continue to be placed in the macro task queue, waiting to be removed and executed one by one
EventLoop
- Microtasks and GUI rendering
Browser rendering is performed at the end of each eventLoop run to detect whether to render or not, with only one macro task per round
<script>
document.body.style.background = 'red';
console.log(1)
Promise.resolve().then(() = >{
console.log(2)
document.body.style.background = 'yellow';
})
console.log(3);
</script>
// Order of execution: 1/3/2
// Color change: only yellow is displayed -- the microtask is executed before the interface renders
SetTimeout (() => {}, 0)
// Color change: it may change from red to yellow or it may stay yellow (because browsers refresh frequently)
<script>
document.body.style.background = 'red';
console.log(1)
setTimeout(() = >{
console.log(2)
document.body.style.background = 'yellow';
},0)
console.log(3);
</script>
Copy the code
- Event task
/* Note: the click event is a macro task, but if you execute button.click() directly in code, it does not result in the macro task being triggered by the user's click, but directly in the script, which is equivalent to executing both methods, not asynchronously */
<script>
button.addEventListener('click'.() = >{
console.log('listener1');
Promise.resolve().then(() = >console.log('micro task1'))
})
button.addEventListener('click'.() = >{
console.log('listener2');
Promise.resolve().then(() = >console.log('micro task2'))
})
button.click(); // click1() click2()
</script>
// Output: listener1 / console.log('listener2')/micro Task1 / micro Task2
// If triggered by button clicking, output: Listener1 / micro Task1 / Listener2 / micro Task2
Copy the code
- Timer task
<script>
Promise.resolve().then(() = > {
console.log('Promise1')
setTimeout(() = > {
console.log('setTimeout2')},0);
})
setTimeout(() = > {
console.log('setTimeout1');
Promise.resolve().then(() = > {
console.log('Promise2')})},0);
</script>
// Output: Promise1 / setTimeout1 / Promise2 / setTimeout2
Copy the code
- Task execution interview questions
Async executes and returns a promise
Await console.log(3); Resolve (console.log(3)).then(()=>{console.log(4)})
Await console.log(3) will cause 3 to execute immediately and defer the code below await to the next microtask
console.log(1);
async function async() {
console.log(2);
await console.log(3);
console.log(4);
}
setTimeout(() = > {
console.log(5);
}, 0);
const promise = new Promise((resolve, reject) = > {
console.log(6);
resolve(7);
});
promise.then((res) = > {
console.log(res);
});
async(a);console.log(8);
// Output: 1-6-2-3-8-7-4-5
Copy the code
Promise.resolve().then(() = > {
console.log(0);
return Promise.resolve(4);
}).then((res) = > {
console.log(res);
})
Promise.resolve().then(() = > {
console.log(1);
}).then(() = > {
console.log(2);
}).then(() = > {
console.log(3);
}).then(() => {
console.log(5);
})
// Output: 0-1-2-3-4-5
/** When a promise is returned, it is not immediately processed, but the promise is placed in an asynchronous method for processing (once again generating a new microtask) [return promise.resolve (4); produces twice then] */
Copy the code