preface
JavaScript is single threaded, that is, JavaScript can only execute one task and other tasks can only wait at the same time.
1, Why is JavaScript single threaded?
js is a script language running in the browser, because it often involves operating dom. If it is multi-threaded, it means that multiple tasks can be executed at the same time.
Imagine that if one thread modifies the dom and another thread deletes the dom, the browser does not know which operation to perform first.
Therefore, when js is executed, it will be executed one task by one.
2, Why is it divided into synchronous tasks and asynchronous tasks?
Imagine if the tasks of js are synchronized, what happens when you encounter tasks that need to be delayed, such as timers and network requests?
The page may crash and need to pause for code that takes a long time to execute
Therefore, asynchronous tasks are introduced.
- Synchronization task: the synchronization task does not need to wait, and the execution result can be seen immediately, such as console
- Asynchronous task: asynchronous tasks need to wait for a certain time to see the results, such as setTimeout and network request
3, Event Loop
The of event loop is relatively simple. It is an infinite loop that transitions between the states of "JavaScript engine waiting for tasks", "executing tasks" and "entering sleep state waiting for more tasks".
General algorithm of engine:
- When there are tasks:
- Start with the first task.
- If there are no other tasks, sleep until the task appears, and then go to step 1.
4, Macro and micro tasks
1. Macro task
(macro)task, it can be understood that the code executed by each execution stack is a macro task (including obtaining an event callback from the event queue and putting it into the execution stack for execution each time).
Task (code) | Macro task | environment |
---|---|---|
script | Macro task | browser |
event | Macro task | browser |
Network request (Ajax) | Macro task | browser |
setTimeout() timer | Macro task | Browser / Node |
fs.readFile() read file | Macro task | Node |
For example, if you go to the bank to queue up for business, everyone's business is equivalent to a macro task;
2. Micro task
microtask is a part of macro task. Its execution time is after the synchronous code execution and before the next macro task execution.
For example, a person goes to the bank to deposit money. After saving money, he carries out some operations, such as buying commemorative coins, buying financial products and handling credit cards. These are called micro tasks.
5, Task queue
1. Concept
According to the specification, event loops are coordinated through the mechanism of task queue. In an Event Loop, there can be one or more task queues. A task queue is a collection of a series of ordered tasks; Each task has a task source. Tasks from the same task source must be placed in the same task queue, and tasks from different sources will be added to different queues. API s such as setTimeout/Promise are task sources.
In the event cycle, the key steps of each cycle are as follows:
- In this cycle, select the oldest task that enters the queue first, and execute it (once) if any
- Check whether there are micro tasks. If so, execute them continuously until the micro tasks queue is cleared
- Update render (DOM rendering)
- The above is a loop, and the main thread repeats the above steps
On the basis of the above cycle, we need to understand the following points:
- JS is divided into synchronous tasks and asynchronous tasks
- Synchronization tasks are executed on the main thread to form an execution stack
- In addition to the main thread, the host environment manages a task queue. As long as the asynchronous task has run results, an event will be placed in the task queue.
- Once all synchronous tasks in the execution stack are executed (JS engine is idle at this time), the system will read the task queue, add the runnable asynchronous tasks to the executable stack and start execution.
2. Operation mechanism
In the event cycle, each cycle operation is called a tick. The task processing model of each tick is complex, but the key steps are as follows:
- Execute a macro task (get it from the event queue if it is not in the execution stack)
- If a micro task is encountered during execution, it will be added to the task queue of the micro task
- After the macro task is executed, all micro tasks in the current micro task queue will be executed immediately (executed in sequence)
- After the execution of the current macro task, start checking the rendering, and then the GUI thread takes over the rendering
- After rendering, the JS thread continues to take over and start the next macro task (get from the event queue)
6, Testing
Can you answer the following questions correctly? Leave the answers in the comments area~
1. Question 1
The code is as follows (example):
console.log(1) setTimeout(function() { console.log(2) }, 0) const p = new Promise((resolve, reject) => { resolve(1000) }) p.then(data => { console.log(data) }) console.log(3)
2. Question 2
The code is as follows (example):
console.log(1) setTimeout(function() { console.log(2) new Promise(function(resolve) { console.log(3) resolve() }).then(function() { console.log(4) }) }) new Promise(function(resolve) { console.log(5) resolve() }).then(function() { console.log(6) }) setTimeout(function() { console.log(7) new Promise(function(resolve) { console.log(8) resolve() }).then(function() { console.log(9) }) }) console.log(10)
3. Question 3
The code is as follows (example):
console.log(1) setTimeout(function() { console.log(2) }, 0) const p = new Promise((resolve, reject) => { console.log(3) resolve(1000) // Mark as successful console.log(4) }) p.then(data => { console.log(data) }) console.log(5)
4. Question 4
The code is as follows (example):
new Promise((resolve, reject) => { resolve(1) new Promise((resolve, reject) => { resolve(2) }).then(data => { console.log(data) }) }).then(data => { console.log(data) }) console.log(3)
5. Question 5
The code is as follows (example):
setTimeout(() => { console.log(1) }, 0) new Promise((resolve, reject) => { console.log(2) resolve('p1') new Promise((resolve, reject) => { console.log(3) setTimeout(() => { resolve('setTimeout2') console.log(4) }, 0) resolve('p2') }).then(data => { console.log(data) }) setTimeout(() => { resolve('setTimeout1') console.log(5) }, 0) }).then(data => { console.log(data) }) console.log(6)
6. Question 6
The code is as follows (example):
<script> console.log(1); async function fnOne() { console.log(2); await fnTwo(); // The right combination executes the code on the right first, and then waits console.log(3); } async function fnTwo() { console.log(4); } fnOne(); setTimeout(() => { console.log(5); }, 2000); let p = new Promise((resolve, reject) => { // The function in new Promise() will execute all the code immediately console.log(6); resolve(); console.log(7); }) setTimeout(() => { console.log(8) }, 0) p.then(() => { console.log(9); }) console.log(10); </script> <script> console.log(11); setTimeout(() => { console.log(12); let p = new Promise((resolve) => { resolve(13); }) p.then(res => { console.log(res); }) console.log(15); }, 0) console.log(14); </script>
summary
Believe in yourself