返回

如影随形 JS运行机制:揭秘微任务与宏任务

前端

浏览器事件循环——同步与异步的交响曲

事件循环是浏览器用来协调任务执行的一套机制。它负责在主线程上执行JavaScript代码,并管理同步任务和异步任务的执行顺序。同步任务是指那些需要立即执行的任务,而异步任务是指那些可以在以后执行的任务。

同步任务与异步任务——谁先谁后?

同步任务会在当前执行栈中立即执行。这意味着,当遇到一个同步任务时,浏览器会暂停所有其他任务的执行,直到这个同步任务完成。例如,变量声明、函数调用等都是同步任务。

异步任务则会在一个专门的异步队列中等待执行。当主线程上的所有同步任务执行完成后,浏览器会从异步队列中取出一个异步任务并将其放入主线程上执行。例如,定时器、网络请求等都是异步任务。

微任务与宏任务——并肩前行的兄弟

微任务和宏任务都是异步任务的一种。但是,它们的区别在于执行时机。微任务会在当前执行栈中立即执行,而在执行完当前执行栈中的所有同步任务和微任务之后,才会执行宏任务。

因此,在事件循环中,微任务的优先级高于宏任务。这意味着,当遇到一个微任务时,浏览器会暂停所有其他任务的执行,包括宏任务,直到这个微任务完成。

一道面试题引发的思考——微任务与宏任务的执行顺序

console.log(1);
setTimeout(() => {
  console.log(2);
}, 0);
console.log(3);
Promise.resolve().then(() => {
  console.log(4);
});

我们来分析一下这段代码的执行顺序:

  1. 首先,浏览器会执行所有同步任务,即console.log(1)console.log(3)
  2. 然后,浏览器会将setTimeout()中的回调函数放入异步队列中,并继续执行主线程上的任务。
  3. 接着,浏览器会执行Promise.resolve(),并将其回调函数放入微任务队列中。
  4. 当主线程上的所有同步任务和微任务都执行完成后,浏览器会从异步队列中取出setTimeout()中的回调函数并将其放入主线程上执行。
  5. 最后,浏览器会从微任务队列中取出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代码执行的奥秘,并提高编码技能。