返回

站在宏任务与微任务的交界处,见证运行机制的奥秘

前端

引言

在前端开发的世界中,JavaScript 引擎扮演着至关重要的角色,它负责执行我们的代码,让我们能够实现各种各样的交互和动画效果。而在 JavaScript 引擎内部,存在着两个重要的任务队列:宏任务队列和微任务队列。这两个队列协同工作,控制着代码的执行顺序,从而影响着我们应用程序的行为。

宏任务与微任务的概念

宏任务

宏任务是指那些需要较长时间才能完成的任务,比如脚本执行、网络请求、定时器回调函数等。当宏任务队列中存在需要执行的任务时,JavaScript 引擎会按照先进先出的原则依次执行它们。

微任务

微任务是指那些需要在当前脚本执行完成后立即执行的任务,比如 Promise 的 .then() 回调函数、MutationObserver 的回调函数等。微任务队列的优先级高于宏任务队列,这意味着当微任务队列中存在需要执行的任务时,JavaScript 引擎会先执行这些任务,然后再执行宏任务队列中的任务。

宏任务与微任务的相互作用

宏任务和微任务之间存在着密切的相互作用。当一个宏任务正在执行时,如果此时有微任务需要执行,那么 JavaScript 引擎会先暂停宏任务的执行,将微任务加入到微任务队列中,等所有微任务执行完成后,再继续执行宏任务。

这种相互作用可以确保微任务总是优先于宏任务执行,从而保证了某些操作的时序性。例如,当我们在脚本中执行一个网络请求时,网络请求是一个宏任务,而网络请求完成后的回调函数是一个微任务。由于微任务的优先级高于宏任务,因此回调函数会优先于其他宏任务执行,从而确保我们能够及时处理网络请求的结果。

常见示例的代码执行顺序分析

为了更好地理解宏任务和微任务的运行机制,我们来看几个常见的示例:

示例 1

console.log('宏任务 1');
setTimeout(() => {
  console.log('宏任务 2');
}, 0);
Promise.resolve().then(() => {
  console.log('微任务 1');
});
console.log('宏任务 3');

输出:

宏任务 1
微任务 1
宏任务 3
宏任务 2

在这个示例中,宏任务 1 和宏任务 3 是按照先进先出的原则依次执行的。而微任务 1 是在宏任务 1 执行完成后立即执行的,因为微任务的优先级高于宏任务。宏任务 2 是在所有微任务执行完成后执行的,因为它是最后一个进入宏任务队列的任务。

示例 2

console.log('宏任务 1');
setTimeout(() => {
  console.log('宏任务 2');
}, 0);
Promise.resolve().then(() => {
  console.log('微任务 1');
  setTimeout(() => {
    console.log('微任务 2');
  }, 0);
});
console.log('宏任务 3');

输出:

宏任务 1
微任务 1
宏任务 3
微任务 2
宏任务 2

在这个示例中,微任务 1 是在宏任务 1 执行完成后立即执行的。而微任务 2 是在微任务 1 执行完成后进入微任务队列的,但由于宏任务 3 已经开始执行,所以微任务 2 需要等到宏任务 3 执行完成后才能执行。宏任务 2 是在所有微任务执行完成后执行的,因为它是最后一个进入宏任务队列的任务。

总结

宏任务和微任务是 JavaScript 中重要的概念,理解它们的运行机制对于编写出高效、稳定的代码至关重要。在本文中,我们分析了宏任务和微任务的概念、相互作用以及常见的代码执行顺序,希望能帮助你更好地掌握这方面的知识。