一、宏任务和微任务的概念
宏任务和微任务是浏览器异步执行任务时的两种不同类型。当浏览器异步执行一个任务时,会首先将任务添加到任务队列中,然后在执行栈清空后,从任务队列中取出队列头的任务执行。
其中,包括一类称为宏任务(macro task)的任务,又称为 task。
还有一类称为微任务(micro task)的任务,又称为 jobs。
它们之间的区别在于它们被添加到任务队列中的时机以及执行的优先级。
二、宏任务和微任务的执行时机
JavaScript 引擎会维护一个执行栈,也称为调用栈(call stack)。执行栈采用后进先出(LIFO)的原则。
每当 JavaScript 引擎执行一个函数时,它会将该函数加入到执行栈的顶部。当该函数执行结束后,JavaScript 引擎会将它从栈中弹出。
当执行栈被清空时,JavaScript 引擎会从任务队列中取出一个任务进行执行。
可见,宏任务和微任务的执行时机是不同的。
宏任务通常包括以下几种:
– setTimeout 和 setInterval 回调函数
– I/O 操作的回调函数
– 事件的回调函数
– setImmediate 回调函数(Node.js 独有)
而微任务通常包括以下几种:
– Promise 回调函数
– process.nextTick 回调函数(Node.js 独有)
三、宏任务和微任务的优先级
在执行栈清空后,JavaScript 引擎会优先处理微任务队列中的任务,直到队列为空,然后再在宏任务队列中取出一个任务执行。也就是说,微任务的优先级高于宏任务。
举个例子:
“`javascript
setTimeout(() => {
console.log(‘setTimeout’);
}, 0);
Promise.resolve().then(() => {
console.log(‘Promise’);
});
“`
上述代码中,setTimeout() 和 Promise.resolve().then() 都是异步操作,会被添加到宏任务队列和微任务队列中。当执行栈中的所有代码执行完毕后,JavaScript 引擎会先执行微任务队列中的 Promise,再执行宏任务队列中的 setTimeout。因此,上述代码执行结果为:
Promise
setTimeout
四、宏任务和微任务实例
实例1:
“`javascript
console.log(1);
setTimeout(() => {
console.log(2);
}, 0);
Promise.resolve().then(() => {
console.log(3);
});
console.log(4);
“`
执行过程:
1. 打印 1
2. 添加定时器回调函数到宏任务队列中
3. 添加 Promise 回调函数到微任务队列中
4. 打印 4
5. 执行微任务队列中的 Promise
6. 执行宏任务队列中的 setTimeout 回调函数
输出结果为:
1, 4, 3, 2
实例2:
“`javascript
console.log(‘start’);
setTimeout(() => {
console.log(‘setTimeout’);
}, 0);
Promise.resolve().then(() => {
console.log(‘Promise 1’);
}).then(() => {
console.log(‘Promise 2’);
});
console.log(‘end’);
“`
执行过程:
1. 打印 start
2. 添加定时器回调函数到宏任务队列中
3. 添加 Promise 回调函数到微任务队列中
4. 打印 end
5. 执行微任务队列中的 Promise 1
6. 执行 Promise 1 中的 then 回调函数,并将 Promise 2 添加到微任务队列中
7. 执行微任务队列中的 Promise 2
8. 执行宏任务队列中的 setTimeout 回调函数
输出结果为:
start, end, Promise 1, Promise 2, setTimeout
总结
在 JavaScript 中,宏任务和微任务的概念有助于我们理解异步代码的执行规则。在掌握了它们之间的区别和优先级后,我们能更加准确地理解和编写异步代码,从而提高代码的效率。
原创文章,作者:小蓝,如若转载,请注明出处:https://www.506064.com/n/183057.html