如影随形 JS运行机制:揭秘微任务与宏任务
2024-02-26 02:33:36
浏览器事件循环——同步与异步的交响曲
事件循环是浏览器用来协调任务执行的一套机制。它负责在主线程上执行JavaScript代码,并管理同步任务和异步任务的执行顺序。同步任务是指那些需要立即执行的任务,而异步任务是指那些可以在以后执行的任务。
同步任务与异步任务——谁先谁后?
同步任务会在当前执行栈中立即执行。这意味着,当遇到一个同步任务时,浏览器会暂停所有其他任务的执行,直到这个同步任务完成。例如,变量声明、函数调用等都是同步任务。
异步任务则会在一个专门的异步队列中等待执行。当主线程上的所有同步任务执行完成后,浏览器会从异步队列中取出一个异步任务并将其放入主线程上执行。例如,定时器、网络请求等都是异步任务。
微任务与宏任务——并肩前行的兄弟
微任务和宏任务都是异步任务的一种。但是,它们的区别在于执行时机。微任务会在当前执行栈中立即执行,而在执行完当前执行栈中的所有同步任务和微任务之后,才会执行宏任务。
因此,在事件循环中,微任务的优先级高于宏任务。这意味着,当遇到一个微任务时,浏览器会暂停所有其他任务的执行,包括宏任务,直到这个微任务完成。
一道面试题引发的思考——微任务与宏任务的执行顺序
console.log(1);
setTimeout(() => {
console.log(2);
}, 0);
console.log(3);
Promise.resolve().then(() => {
console.log(4);
});
我们来分析一下这段代码的执行顺序:
- 首先,浏览器会执行所有同步任务,即
console.log(1)
和console.log(3)
。 - 然后,浏览器会将
setTimeout()
中的回调函数放入异步队列中,并继续执行主线程上的任务。 - 接着,浏览器会执行
Promise.resolve()
,并将其回调函数放入微任务队列中。 - 当主线程上的所有同步任务和微任务都执行完成后,浏览器会从异步队列中取出
setTimeout()
中的回调函数并将其放入主线程上执行。 - 最后,浏览器会从微任务队列中取出
Promise.resolve()
中的回调函数并将其放入主线程上执行。
因此,这段代码的输出结果为:
1
3
4
2
微任务与宏任务——举个栗子
为了更好地理解微任务和宏任务,我们举一个简单的例子。
const promise = Promise.resolve();
promise.then(() => {
console.log('微任务');
});
setTimeout(() => {
console.log('宏任务');
}, 0);
在这段代码中,我们首先创建一个Promise
对象,并在then()
方法中注册了一个回调函数。然后,我们使用setTimeout()
函数创建一个宏任务。
当这段代码执行时,首先会执行所有同步任务,即创建Promise
对象和注册回调函数。然后,浏览器会将setTimeout()
中的回调函数放入异步队列中,并继续执行主线程上的任务。
接着,浏览器会执行Promise.resolve()
,并将其回调函数放入微任务队列中。
当主线程上的所有同步任务和微任务都执行完成后,浏览器会从异步队列中取出setTimeout()
中的回调函数并将其放入主线程上执行。
最后,浏览器会从微任务队列中取出Promise.resolve()
中的回调函数并将其放入主线程上执行。
因此,这段代码的输出结果为:
微任务
宏任务
微任务与宏任务——它们的重要性
微任务和宏任务在JavaScript开发中非常重要。通过理解它们的概念和区别,我们可以更好地控制代码的执行顺序,并编写出更加健壮和可维护的代码。
例如,我们可以利用微任务来实现一些需要立即执行的任务,例如更新UI。这样可以避免UI卡顿,并提供更好的用户体验。
结语
在本文中,我们深入探讨了JavaScript运行机制中的微任务和宏任务。我们了解了浏览器事件循环的运作方式,同步任务和异步任务的执行顺序,以及微任务和宏任务的区别和关联。通过深入理解这些概念,您将掌握JavaScript代码执行的奥秘,并提高编码技能。