Web front-end knowledge: micro-tasks and macro-tasks in js

Enter picture description

What are microtasks and macrotasks in js

In the JavaScript engine, tasks are divided into two types: microtasks and macrotasks. A microtask is a task that is executed immediately after the execution of the current task, and it can be regarded as a task added at the “tail” of the current task. Common microtasks include Promise callbacks and process.nextTick. Macrotasks are tasks that need to be queued for execution when the JavaScript engine is idle. Common macro tasks include setTimeout, setInterval, I/O operations, DOM events, and more. The JavaScript engine executes all microtasks in the current task before executing the first task in the macrotask queue. This process will be repeated continuously until all the tasks in the macro task queue are executed.

Why does JS distinguish between microtasks and macrotasks

The reason why JavaScript distinguishes between microtasks and macrotasks is because the execution order of microtasks and macrotasks is different, which has an important impact on the realization of some asynchronous operations in Web development. In JavaScript, microtasks are executed before macrotasks. This means that all microtasks will be executed immediately after the execution of the current task, while the macrotask will only be executed after all microtasks have been executed. This execution order guarantees the priority of microtasks and can avoid some problems, such as race conditions that may occur when processing Promise objects. For example, when we use the Promise object, it returns a Promise instance and puts the callback function into the microtask queue. When the state of the Promise changes, it will immediately execute the callback function in the microtask queue instead of waiting for the current task to end before executing it. This feature can guarantee the execution order of Promise callback functions, avoid race conditions, and make the code more reliable. On the other hand, the execution of the macro task will be executed after the end of the current task, which means that some time-consuming operations can be put into the macro task queue, so as to avoid blocking the execution of the current task. For example, we can put some code that needs to wait for a period of time to be executed into the callback function of setTimeout, so that the page can remain responsive while executing these codes and improve user experience. Therefore, the reason why JavaScript distinguishes between microtasks and macrotasks is to ensure the correctness and performance of asynchronous operations.

Execution order of microtasks and macrotasks in JS

  1. The current code (synchronous tasks) is executed first until the first macrotask or microtask is encountered.
  2. If a microtask is encountered, it is added to the microtask queue and the synchronization task continues.
  3. If a macro task is encountered, it will be added to the macro task queue to continue to execute the synchronous task.
  4. After the current task is executed, the JavaScript engine will first execute all tasks in the microtask queue until the microtask queue is empty.
  5. Then execute the first task in the macrotask queue until the macrotask queue is empty.
  6. Repeat steps 4 and 5 until all tasks are executed. It should be noted that microtasks have a higher priority than macrotasks, so in the same task, if there are both microtasks and macrotasks, the microtasks will be executed first. In different tasks, the execution priority of the macro task is higher than that of the micro task, so after a macro task is executed, it will execute the tasks in the next macro task and micro task queue. For example, suppose there is a setTimeout and a Promise in the current code, which correspond to a macrotask and a microtask respectively. Then the order of execution is as follows:
    1). Execute the current code, add setTimeout and Promise to the macro task and micro task queue.
    2). After the current task is executed, the JavaScript engine first executes the Promise callback function in the microtask queue.
    3). After the microtask queue is empty, execute the setTimeout callback function in the macrotask queue. It should be noted that in some special cases, the execution order of microtasks and macrotasks may change. For example, when using MutationObserver to monitor DOM changes, it will be regarded as a microtask, but its execution order may be different than other Microtasks are further back. Therefore, the execution order of microtasks and macrotasks needs to be understood and handled on a case-by-case basis.

What are js microtasks and macrotasks

Microtask: Promise callback function, process.nextTick, Object.observe (deprecated), MutationObserver.
Macro tasks: setTimeout, setInterval, setImmediate (Node.js only), requestAnimationFrame, I/O operations, UI rendering.

It should be noted that different JavaScript engines may have some differences. Some tasks may be used as both micro tasks and macro tasks. For example, in some browsers, when using MutationObserver to monitor DOM changes, it will be regarded as a A microtask, but in some versions of Node.js it is treated as a macrotask. In addition, it should be noted that the Promise callback function is a microtask, but its internal code may contain other asynchronous operations. These asynchronous operations may be microtasks or macrotasks, so when dealing with Promise, it needs to be considered that it may contain other asynchronous operations.

Case

1. Micro task: Promise callback function, macro task: setTimeout callback function

console.log('start');
setTimeout(() => console. log('setTimeout'), 0);
Promise.resolve().then(() => console.log('Promise'));
console.log('end');
// start
// end
//Promise
// setTimeout

Analysis: First output start, and then register a callback function through the setTimeout method, which will be added to the macro task queue. Then create a Promise instance and register a callback function through the then method, which will be executed when the state of the Promise object changes. Then output end. Because the Promise callback function is a microtask, it will be added to the microtask queue, waiting to be executed. After the synchronization tasks of the main thread are executed, the JavaScript engine will first execute the tasks in the microtask queue, output Promise, then execute the tasks in the macrotask queue, and output setTimeout .

2. Micro task: process.nextTick callback function, macro task: setImmediate callback function

console.log('start');
setImmediate(() => console. log('setImmediate'));
process.nextTick(() => console.log('process.nextTick'));
console.log('end');
// start
//end
// process. nextTick
// setImmediate

Analysis: In the Node.js environment, the process.nextTick callback function is at the top of the microtask queue, with a higher priority than the Promise callback function. The setImmediate callback function is at the end of the macro task queue. Therefore, the above code will first output start, and then output end. After the synchronization tasks of the main thread are executed, the JavaScript engine will first execute the tasks in the microtask queue, output process.nextTick, then execute the tasks in the macrotask queue, and output setImmediate code>.

3. Micro task: Promise callback function, macro task: requestAnimationFrame callback function

console.log('start');
requestAnimationFrame(() => console. log('requestAnimationFrame'));
Promise.resolve().then(() => console.log('Promise'));
console.log('end');
// start
// end
//Promise
// requestAnimationFrame

Analysis: First output start, and then register a callback function through the requestAnimationFrame method, which will be added to the macro task queue. Then create a Promise instance and register a callback function through the then method, which will be executed when the state of the Promise object changes. Then output end. Because the Promise callback function is a microtask, it will be added to the microtask queue, waiting to be executed. After the synchronous tasks of the main thread are executed, the JavaScript engine will first execute the tasks in the micro task queue, output Promise, then execute the tasks in the macro task queue, and output requestAnimationFrame .

4. Micro task: Promise callback function, macro task: XMLHttpRequest callback function

console.log('start');
const xhr = new XMLHttpRequest();
xhr.open('GET', 'https://jsonplaceholder.typicode.com/users/1');
xhr.onload = () => console.log('XMLHttpRequest');
xhr. send();
Promise.resolve().then(() => console.log('Promise'));
console.log('end');
// start
// end
//Promise
//XMLHttpRequest

Analysis: First output start, then create an XMLHttpRequest object, and send a GET request through the open method and send method. Then, a callback function is registered through the onload method, which will be executed after the request is successful. Then create a Promise instance and register a callback function through the then method, which will be executed when the state of the Promise object changes. Then output end. Because the Promise callback function is a microtask, it will be added to the microtask queue, waiting to be executed. After the synchronization task of the main thread is executed, the JavaScript engine will first execute the tasks in the microtask queue, output Promise, and then wait for the callback function of the XMLHttpRequest object to execute. When the request is successful, the JavaScript engine will execute the tasks in the macro task queue and output XMLHttpRequest.

Conclusion

Hand in hand continues to share all kinds of knowledge and software for you, welcome to visit, follow, discuss and leave your care?