首页/文章/javascript

能说说你对宏任务 和 微任务 的理解吗

2023-12-06
20197 分钟
...

一、背景

js 是一种单线程语言,只有一条通道,那么在任务多的情况下,就会出现堵塞,这种情况下就产生了 多线程,那么就产生了同步任务和异步任务。

同步任务: 在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务。是由 js 执行栈/回调栈执行

异步任务: 不进入主线程、而进入任务队列的任务,当主线程中的任务运行完成了,才会从任务队列中取出异步任务,放入主线程中执行

二.宏任务和微任务

微任务和宏任务都是异步任务,它们都属于一个队列

宏任务:script、setTimeout、setInterval、postMessage、MessageChannel、及Node.js 环境中的setImmediate.

微任务:Promise.then、Object.observe、MutationObserver、及Node.js 环境中的process.nextTick.

宏任务

宏任务是由宿主环境发起的,比如浏览器、Node等,宏任务的异步代码有:

  • script(代码块)

  • setTimeout / setInterval 定时器

  • setImmediate 定时器

  • ......等等

微任务

微任务是由JS引擎发起的,微任务的异步代码有:

  • process.nextTick (node)

  • Promise.then( )/catch( ) 。注意,Promise本身同步,只是它里面的then/catch的回调函数是异步的微任务

  • Async/Await

  • Object.observe

  • ......等等

三、任务的执行顺序

有人说宏任务先于微任务执行,也有人说微任务先于宏任务执行

其实,由于整个 script 身就是一个大的宏任务,所以在执行任务时,肯定是执行script这个大的宏任务里面的代码,因此,我们也可以说是宏任务优先于微任务

但是如果我们忽略script这个大的宏任务,仅仅只讨论script里包含的任务代码块,那么任务的执行顺序就一定是微任务优先于宏任务

在这里,我们就先忽略script执行顺序就为: 同步任务 ---> 微任务 ---> 宏任务

案例演示:下面代码的执行结果是什么?

console.log(1);
setTimeout(() => {
  console.log(2);
}, 0);

const p = new Promise((resolve, reject) => {
  console.log(3);
  resolve("success"); 
  console.log(4);
});

p.then((value) => {
  console.log(value);
});

console.log(5);

我们可以通过文章开头的理论解释,将上面代码分为同步任务、微任务、宏任务三块,

哪些代码属于同步任务,哪些代码属于微任务,哪些代码属于宏任务,如下图所示:

将我们分析好的代码,分开放在相应的队列里,可得到以下代码执行的流程图示:

所以这个案例,最终得到的执行结果就是: 1 3 4 5 “success” 2

四、详细讲解宏任务和微任务的区别

首先,宏任务和微任务的执行时机是不同的。

宏任务会在主线程执行完毕后被执行,而微任务会在主线程执行完毕之前立即执行。

其次,宏任务和微任务的优先级也是不同的。在 JavaScript 中,微任务的优先级比宏任务高,也就是说,如果微任务队列和宏任务队列中都有任务需要执行,微任务会先于宏任务执行。

另外,宏任务和微任务对于 JavaScript 事件循环的影响也是不同的。宏任务会触发事件循环,而微任务不会触发事件循环,而是在主线程上的同步任务执行完毕后立即执行。

此外,宏任务和微任务在实际应用中有着不同的用途。宏任务通常用于与浏览器渲染相关的任务,如 setTimeout 和 requestAnimationFrame,而微任务通常用于异步操作,如 Promise.then 和 async/await。

通过理解宏任务和微任务的区别,我们可以更好的优化代码的性能,例如避免在微任务中执行大量耗时的操作。

总之,宏任务和微任务是 Javascript 中非常重要的概念,对于更好的理解 JavaScript 的执行机制和优化代码的性能是非常有帮助的。

五、小试牛刀

请说一说以下代码的执行顺序和结果:

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

解答:

  • 首先,输出 1 和 6,之后,第一层 setTimeout 中的回调函数执行,输出 2。
  • 之后,执行第二层 setTimeout 中的回调函数,输出 3。
  • 然后微任务 Promise.resolve()执行并输出 5,
  • 最后执行第二层 setTimeout 中的回调函数,输出 4。

在这个例子中,可以看到微任务和宏任务在嵌套的 setTimeout 中被调度了,这就使得事件循环变得更加复杂。 具体的执行顺序如下:首先执行第一个 setTimeout 的回调函数,执行完之后把第二层 setTimeout 的回调函数和 Promise.resolve 放入微任务队列,紧接着执行第二层 setTimeout 的回调函数,执行完之后把第三层 setTimeout 的回调函数放入微任务队列,最后执行微任务队列中的任务,微任务 Promise.resolve 先于第三层 setTimeout 的回调函数执行。

六、总结

1.宏任务会在主线程执行完毕后被执行,而微任务会在主线程执行完毕之前立即执行。
2.宏任务会触发事件循环,而微任务不会触发事件循环,而是在主线程上执行完毕后立即执行。

如果您觉得这篇文章有帮助,请点个赞吧~

分享文章

相关文章

更多文章 →
javascript2025-09-18
JavaScript 的多线程能力:Worker
如果你写过一些计算量稍大的 JavaScript 代码,比如图像处理、大量数据排序或者复杂的算法,你几乎肯定遇到过浏览器“卡死”的现象。点击页面没反应,动画也停了,就像整个世界都静止了。 这就是主线程被阻塞的典型后果。因为主线程既要负责执行 JavaScript,又要负责渲染页面、响应用户操作,一旦它被繁重的计算任务占满,就无暇顾及其他,用户体验便直线下降。 这个问题的根源,正是“主线程是单线程的”。那么,如何解决呢? 答案很简单:把这...
学习面试
javascript2025-09-10
手把手教你实现一个EventEmitter
你是不是也遇到过这种情况:代码里各种事件监听和触发,回调函数套了一层又一层,最后自己都理不清哪个事件先触发、哪个后触发了? 别担心,今天我就带你从零开始实现一个自己的事件触发器(EventEmitter),让你彻底掌握事件驱动的精髓,代码清晰度直接提升200%! 为什么要懂EventEmitter? 先说说为什么我们要关心这个。Node.js的核心就是事件驱动,比如文件读写、网络请求,都是通过事件来处理的。不会EventEmitter,...
学习面试
javascript2025-08-09
Web Worker 多线程魔法
你是否曾遇到过网页因为复杂计算而卡顿的情况?今天,让我们一起探索Web Worker的神奇世界,看看如何用多线程技术解决性能瓶颈,并实现流畅的图片压缩功能! 为什么需要Web Worker? 想象一下,你在一个繁忙的餐厅里,只有一位服务员(主线程)负责点餐、上菜、结账所有工作。当客人突然暴增时,这位服务员就会手忙脚乱,其他客人只能干等着… 这就是JavaScript的现状—— 单线程 !所有任务都在一个线程中排队执行,一旦遇到复杂计算(...
学习面试
javascript2025-08-07
🌐AST抽象语法树
AST 是前端开发中一个非常重要的概念,它就像是代码的“编译器”,能够帮助我们理解和操作代码。本文将深入探讨 AST 的原理和应用,带你从零开始了解 AST。 一、什么是 AST? AST(抽象语法树)是一种树形结构,用于表示程序代码的语法结构。它将代码分解为一系列的节点,每个节点代表代码中的一个元素,如变量、函数、表达式等。AST 是编译器和解释器的基础,也是代码分析和转换的关键工具。 1\. AST 的结构 AST 的结构通常包括以...
学习面试
javascript2025-08-05
打字机效果是如何实现的
分析效果 使用 AI 对话的时候,文字是一个字一个字蹦出来的?它不是等所有内容生成完毕后一次性展示,而是以一种流畅、实时的“打字机”效果呈现,这种体验的背后,隐藏着一种高效的Web技术。它就是 服务器推送事件(Server Sent Events,简称 SSE) 什么是 SSE 从根本上说,SSE 是一种允许服务器 单向 、 持续 地向客户端(浏览器)推送数据的Web技术。 可以把它想象成一个 电台广播 : 服务器 是广播电台,持续不断...
学习面试
javascript2025-08-04
Promise 从原理到实现
前言 是 异步编程的核心概念之一,它为我们提供了一种更优雅的方式来处理异步操作。 本文将全面剖析 的工作原理,并逐步实现一个符合 规范的 。 正文 一、Promise 基础概念 代表一个异步操作的最终完成(或失败)及其结果值。它有 种状态: 1. pending : ,既不是成功,也不是失败状态 2. fulfilled :意味着操作 完成 3. rejected :意味着操作 状态一旦改变就不能再变,只能从 变为 ,或从 变为 。 二...
学习面试

评论

请登录后发表评论

去登录
加载评论中...

目录