preface
Let’s look at a few simple lines of code before we learn the concept:
console.log(1)
setTimeout(() = > {
console.log(2);
}, 0);
const promise = new Promise((resolve, reject) = > {
console.log(3);
resolve();
});
promise.then(() = > {
console.log(4);
});
console.log(5);
Copy the code
The following output is displayed:
1
3
5
4
2
Copy the code
Is it what you thought it would be? I often run into this problem at work where I want it to execute first and then execute later, resulting in all sorts of issues with page rendering. To understand why the output looks like this, we need to understand the browser’s event loop mechanism.
Event loop mechanism
JavaScript Event Loop mechanism is divided into browser Event Loop mechanism and Node Event Loop mechanism. The implementation technology of the two is different. Browser Event Loop is a specification defined in HTML, while Node Event Loop is implemented by libuv library. We’ll just focus on the browser event loop.Browser execution of JS code can be roughly divided into three steps, and the loop of these three steps constitutes the JS event loop mechanism (as shown in the figure above).
-
The main thread (JS engine thread) performs macro tasks (JS whole code or callback function). During execution, objects will be stored in the heap, function parameters and local variables will be added to the stack, and after execution, the heap will be released or the stack will exit. After executing this macro task, the queue of microtasks is determined to be empty. If not, all the microtasks are fetched and executed in sequence. If any Web APIs are triggered during this process, the second step is taken.
-
Call the Web API and add the callback function to the event queue when appropriate. For example, setTimeout(Callback1, 1000) creates a timer and listens in another thread (the browser-timed thread) to see if the timer expires. When the timer expires, the corresponding callback1 is added to the event callback queue.
-
After the microtask in the first step completes, the event callback queue is determined to be empty. If it is not empty, the first callback to be queued is fetched and executed as if it were the first step. If it is empty, the main thread is waited or suspended as appropriate.
Summary: execute a macro task first, then execute the corresponding micro task generated by this macro task, and then execute the following macro task, and so on.
Macro task, micro task
- Macro task macro – a task
- Script overall code, setTimeout, setInterval, I/O operation, UI rendering
- Micro task micro – a task
- New Promise(). Then contents, MutationObserve (front-end backtracking)
Now that we know about the classification of macro and microtasks and the order in which JS executes them, let’s look at the example at the beginning
console.log(1)
setTimeout(() = > {
console.log(2);
}, 0);
const promise = new Promise((resolve, reject) = > {
console.log(3);
resolve();
});
promise.then(() = > {
console.log(4);
});
console.log(5);
Copy the code
First macro task (overall code) : When setTimeout is encountered, it joins the macro task queue (waiting for execution), when promise is encountered, it normally outputs 3, encountered. Then () it joins the micro task queue, outputs 5, this macro task is completed, and the total output is 1 3 5 When the first macro task is completed, clear the micro task queue generated by this macro task. Output 4 checks the macro task queue, finds another macro task setTimeout, executes the task, output 2 the final result is 1, 3, 5, 4, 2
Strike while the iron is hot
Js execution sequence: first execute a macro task, then execute the corresponding micro task generated by this macro task, and then execute the following macro task, and so on.
function func1() {
console.log('func1');
Promise.resolve().then(() = > {
console.log('microtask.promise1');
});
}
function func2() {
console.log('func2');
Promise.resolve().then(() = > {
console.log('microtask.promise2');
});
}
function main() {
func1();
func2();
setTimeout(func1, 0);
setTimeout(func2, 0);
}
main()
Copy the code
The following output is displayed:
// First macro task (overall code) executed
func1
func2
microtask.promise1
microtask.promise2
// Second macro task (setTimeout(func1, 0))
func1
microtask.promise1
// Third macro task (setTimeout(func2, 0))
func2
microtask.promise2
Copy the code
Are you getting it? You have to believe you’re the best.