preface
Author: @Xiaoyao Yao Loves Candy Candy
In our last post @tdGarden said: It’s spring and everything is alive again and everyone is too busy dating to blog. Then he sent me a picture in the group:
All right, let’s get down to business and talk about the Event Loop. This article is a summary and sorting of the learning of Event Loop in these days. I refer to many articles of big wigs. If there are any mistakes, please correct them.
Let’s start with single threads
Js is known to be a single-threaded language. Why single thread? Let’s say we have two threads. One thread wants to add content to a DOM node, and the other thread wants to delete it. Of course, there is a multi-threaded solution to multi-threading, locking ah, but this will introduce locking, state synchronization and other issues.
Js is a browser scripting language. Its main purpose is to interact with users and operate DOM. Multi-threading will bring very complex synchronization problems.
Ok, single thread then. However, single threading brings with it the problem of single threading. With only one thread, tasks have to be queued, and if the previous task takes a long time to execute (ajax requests for background data), subsequent tasks have to wait.
The Event Loop is here to back up the single-threaded mess.
Event Loop
Before moving on, you should know the basic concepts of stack, queue, synchronous task, asynchronous task, and execution stack.
There is a very detailed article on execution stacks recommended: JavaScript deep execution Context stacks
See the picture below:
-
Js in the execution of the code, the code first into the execution stack, the code may contain some synchronous tasks and asynchronous tasks.
-
The synchronization task is executed immediately, and then the stack is removed, over.
-
Asynchronous tasks are common Ajax requests, setTimeout, etc. When code calls these apis, the WebAPIs handle these issues and the execution stack continues.
-
When the asynchronous task has a result to run (when the Ajax request result returns), the WebAPIs put the corresponding callback function on the task queue.
-
When the stack is empty, the first function in the task queue is read and pushed onto the stack.
Step 5 is repeated repeatedly. If the execution stack is empty, the system pushes the first function in the task queue to continue execution. This process is repeated over and over again. This is called an Event Loop.
Let’s look at a simple demo.
console.log(1);
setTimeout(() => {
console.log(2);
}, 2000);
console.log(3);
Copy the code
console.log(1)
Synchronization task, output 1setTimeout
Asynchronous tasks, handed over to Webapis, and after 2 seconds,console.log(2)
Entering a Task queueconsole.log(3)
To synchronize tasks, output 3- When the stack is empty, the system reads the events in the task queue
- perform
console,log(2)
And the output 2
Macro tasks & micro tasks
That’s not the end of it, of course. I’m sure you’ve seen process.nextTick and promise, where the order of execution can get a little complicated. Scroll down.
Microtasks, macro tasks, and event-loops use very common examples to explain the difference between macro tasks and microtasks, so I won’t bother here. It’s ok if you don’t want to know, because there are only a few common macro tasks and micro tasks. Just remember them.
- Common macro tasks:
Script (whole code)
,setTimeout
,setInterval
,I/O
,setImmedidate
- Common microtasks:
process.nextTick
,MutationObserver
,Promise.then catch finally
Process. nextTick and setImmidate are Node only.
Also, Process. nextTick has a queue-jumping operation, meaning that when it enters the microtask queue, it will be queued in front of all other microtasks except process.nextTick.
So, the task queue we mentioned above consists of a macro task queue and a micro task queue. Each time the execution stack is empty, the system will first process the microtask queue, process all the tasks in the microtask queue, and then process the macro task.
Do two problem
After all that, let’s try two questions.
new Promise(resolve => {
resolve(1);
Promise.resolve().then(() => console.log(2));
console.log(4);
}).then(t => console.log(t));
console.log(3);
Copy the code
Hahahhhhh I moved out of the ruan teacher’s question.
- First of all,
new Promise
To perform,resolve(1)
Indicates that the state of the created Promise object has changed to Resolved Promise.resolve()
A promise object is created, and the anonymous callback function inside then enters the microtask queue, which is called[() => console.log(2)]
- The output of 4
new Promise
The anonymous callback in the then function of the[() => console.log(2), t => console.log(t)]
- The output of 3
So, the final output order is 4, 3, 2, 1.
If you don’t understand, I think you should go over the promise.
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');
});
process.nextTick(() => {
console.log('nextTick');
})
console.log('script end');
Copy the code
This is a bad job interview question. I can’t believe you haven’t. Without further ado, let’s analyze EMMMMM. I recommend that you do it yourself first and then move on.
Don’t be nervous to see async/await, it’s just syntactic sugar. Async means that an asynchronous operation is performed in a function, and the code before an await operation should be executed, the expression to the right of an await operation should be executed, and the code following the await operation is blocked. When a non-Promise object is returned, the following code is executed; When the Promise object is returned, wait until the Promise object is resolved.
The code goes into promise.then.
- The output
script start
- WebAPIs will be available in 0s (oh, like the shortest is 4ms)
setTimeout
The anonymous callback function inside is thrown into the macro task queue, denoted as['setTimeout']
(Remember that the callback is thrown into the task queue, function!) - The output
async1 start
- The output
async2
- To the output
async1 end
The code is thrown into the microtask queue, which is['async1 end']
- The output
promise1
promise
Object state changes toresolved
promise.then
Where, the anonymous function enters the microtask queue, and the microtask queue is['async1 end', 'promise2']
nextTick
Cut to the head of the microtask queue,['nextTick', 'async1 end', 'promise2']
- The output
script end
- Execution stack is empty
- The output
nextTick
- The output
async1 end
- The output
promise2
- The microtask queue is empty
- The output
setTimeout
conclusion
If after reading this article you still do not understand, then I suggest you can read several articles, a baked cake is not enough to eat, ten is about the same.
This article doesn’t go into details about promises, async/await, and the difference between Node and browser Event loops, but it will help you get a better handle on Event loops.
Eventloop is not terrible. What is terrible is meeting a promise.
Refer to the article
- Understand Event Loop for the last time
- Figure out the JavaScript engine Event Loop
- This time, thoroughly understand the JavaScript execution mechanism
- More on the Event Loop