js中的宏任务和微任务

文章类型:Javascript

发布者:hp

发布时间:2024-12-03

一:概述

端开发中,尤其是在面试中,我们经常听到宏任务(Macro Task)和微任务(Micro Task)这两个概念。这两个概念是在 JavaScript 中任务调度过程中的重要组成部分,那么,他们是什么呢?

二:内容

(一)宏任务(Macro Task)

1:定义:每次执行栈执行的代码当做是一个宏任务(包括每次从事件队列中获取一个事件回调并放到执行栈中执行),每一个宏任务会从头到尾执行完毕,不会执行其他,说白了就是JS主线程执行的任务

2:常用场景:

(1)浏览器事件(如 click、mouseover 等)

(2)定时器任务(如 setTimeout 和 setInterval)

(3)页面渲染(如 回流或重绘)

(4)事件回调(如 I/O、点击事件等)

(5)网络请求 (如 XMLHttpRequest 和 fetch 等)

3:作用:宏任务通常独立于当前任务,并按顺序排队执行

4:代码:

// 事件监听器创建宏任务
const button = document.querySelector("button");

button.addEventListener("click", () => {
  console.log("Button clicked");
});

console.log("Waiting for button click...");

(二)微任务(Micro Task)

1:定义:当前 宏任务执行后立即执行的任务,当 宏任务执行完,会在渲染前,将执行期间所产生的所有 微任务都执行完

2:常用场景

(1)Promise 的回调函数

(2)Async/Await 函数

(3)MutationObserver 的回调函数

(4)process.nextTick(Node.js 环境下)

3:作用:微任务是 JavaScript 中处理异步操作的一种机制,它通过及时响应并在当前任务结束后立即执行,有助于编写更高效和灵活的异步代码

4:代码:

console.log("1");

setTimeout(() => {
  console.log("2");
  Promise.resolve().then(() => console.log("3"));
});

Promise.resolve().then(() => console.log("4"));

console.log("5");

三:区别

(一)执行时机

1:宏任务是由 JavaScript 引擎在执行栈(执行同步任务)和任务队列中的任务之间切换时执行的。按照宏任务队列的顺序执行

2:微任务是在宏任务执行结束,下一个宏任务开始之前执行的任务。在当前宏任务中执行完后立即执行,并按照微任务队列的顺序执行

(二)调度机制

1:宏任务当主线程执行完当前宏任务后,会检查是否存在微任务,如果存在,则会执行所有微任务,然后选择下一个宏任务执行,使用先进先出的调度机制,即它们按照任务的顺序排列,并按顺序执行

2:微任务队列中存在微任务时,会依次执行微任务,直到微任务队列为空,微任务则使用一个任务队列(microtask queue)进行调度,当宏任务执行完毕后,会立即将所有的微任务添加到任务队列中,并按照先进先出的顺序依次执行

四:总结

1:执行一个 宏任务(栈中没有就从 事件队列中获取),执行过程中如果遇到 微任务,就将它添加到 微任务的任务队列中

2:宏任务执行完毕后,立即执行当前 微任务队列中的所有 微任务(依次执行)

3:当前 宏任务执行完毕,开始检查渲染,然后 GUI线程接管渲染

4:渲染完毕后, JS线程继续接管,开始下一个 宏任务(从事件队列中获取)

5:微任务优先级高于宏任务,因此在同一轮事件循环中,微任务会优先执行

五:拓展

(一)事件循环机制(Event Loop)

1:定义:是 JavaScript 引擎用来处理异步任务的一种机制。它负责维护一个任务队列,并按照一定的规则循环执行任务队列中的任务

2:图解:

3:执行流程:

执行同步任务(从上到下逐行执行)->遇到异步任务(添加到微任务队列中)->执行宏任务(当同步任务执行完成,执行宏任务队列任务,如遇到嵌套微任务,则添加到微任务队列)->执行微任务(执行完一个宏任务后,立即执行微任务队列中的所有微任务)->循环执行,直到任务队列为空