JavaScript事件循环:任务队列与微任务队列的执行顺序详解

javascript事件循环:任务队列与微任务队列的执行顺序详解

本文旨在深入剖析JavaScript事件循环机制中任务队列(Task Queue)与微任务队列(Job Queue,也称Microtask Queue)的执行优先级和相互影响。通过具体代码示例,详细解释了setTimeout、Promise等异步操作在事件循环中的调度方式,以及微任务如何优先于任务队列中的任务执行,从而帮助开发者更深入地理解JavaScript的异步编程模型。

JavaScript事件循环机制

JavaScript 是一种单线程语言,这意味着它一次只能执行一个任务。为了处理异步操作,JavaScript 引入了事件循环机制。事件循环不断地检查调用栈(Call Stack)是否为空,如果为空,则从任务队列(Task Queue)中取出第一个任务放入调用栈中执行。执行完毕后,再次检查调用栈,如此循环。

任务队列(Task Queue)与微任务队列(Job Queue)

任务队列和微任务队列都是用于存放待执行任务的队列,但它们的优先级不同。

任务队列(Task Queue):也称为宏任务队列,用于存放诸如 setTimeout、setInterval、I/O 操作等异步任务的回调函数。微任务队列(Job Queue):也称为微任务队列,用于存放诸如 Promise.then、MutationObserver 等异步任务的回调函数。

执行顺序:

立即学习“Java免费学习笔记(深入)”;

执行全局同步代码。当调用栈为空时,检查微任务队列。如果微任务队列不为空,则依次执行微任务队列中的所有微任务。当微任务队列为空时,从任务队列中取出一个任务放入调用栈中执行。重复步骤 2-4。

关键在于,每次从任务队列中取出一个任务执行后,都会立即清空微任务队列,然后再取下一个任务。 这意味着微任务的优先级高于任务队列中的任务。

代码示例分析

以下面的代码为例:

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

这段代码的执行过程如下:

setTimeout 被添加到调用栈,然后被推入 WebAPI,并从调用栈中弹出。setTimeout 的回调函数被放入任务队列。Promise.resolve(‘2’).then(console.log) 被添加到调用栈。Promise.resolve 创建一个已解决的 Promise,其 then 方法的回调函数被放入微任务队列。console.log(‘3’) 被添加到调用栈并执行,输出 3。此时调用栈为空,事件循环检查微任务队列,发现 Promise.then 的回调函数,将其放入调用栈并执行,输出 2。微任务队列为空,事件循环从任务队列中取出 setTimeout 的回调函数,将其放入调用栈并执行,输出 1。

因此,最终的输出结果是 3 2 1。

错误示例分析

下面这段代码容易产生误解:

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

这段代码的输出结果是 3 1,然后一段时间后输出 2。

原因分析:

这段代码中,Promise.resolve 的参数是 setTimeout 的返回值,也就是 setTimeout 的 ID(一个数字)。Promise.resolve 创建一个已解决的 Promise,其值为 setTimeout 的 ID。因此,Promise.then 的回调函数并没有被执行,而 setTimeout 的回调函数仍然被放入任务队列,按照 setTimeout 的执行顺序执行。

正确的理解是:setTimeout 的调用是同步的,它将一个回调函数注册到 WebAPI,并返回一个 timer ID。这个 timer ID 被 Promise.resolve 包裹,并立即resolve。console.log(‘2’) 最终会在 setTimeout 的回调函数中执行,它与 Promise 的状态无关。

总结与注意事项

微任务队列的优先级高于任务队列。每次从任务队列中取出一个任务执行后,都会立即清空微任务队列。Promise.resolve(setTimeout(…)) 这种写法容易产生误解,应该避免。理解事件循环机制对于编写高性能的 JavaScript 代码至关重要。

通过深入理解 JavaScript 的事件循环机制,我们可以更好地控制异步代码的执行顺序,避免出现意外的行为,并编写出更加高效和可靠的 JavaScript 应用。

以上就是JavaScript事件循环:任务队列与微任务队列的执行顺序详解的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1515913.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2025年12月20日 09:40:24
下一篇 2025年12月20日 09:40:44

相关推荐

  • 事件循环在Node.js的哪些版本中有重大变化?

    node.js 10起优化定时器性能与精度;2. 11版改进async_hooks稳定性;3. 12版增强promise拒绝处理;4. 14版引入diagnostics_channel提升监控能力;5. 16版通过v8升级提升执行效率;6. 18版支持实验性fetch api减少依赖,这些演进共同提…

    2025年12月20日 好文分享
    000
  • JavaScript事件循环:任务队列与微任务队列的优先级与依赖关系

    本文旨在深入解析JavaScript事件循环机制中任务队列(Task Queue)和微任务队列(Job Queue,也常称为Microtask Queue)的优先级关系,以及当微任务依赖于任务队列中的任务时,执行顺序如何保证。通过具体示例,阐明了Promise等异步操作与setTimeout等定时器…

    2025年12月20日
    000
  • 在 React 函数式组件中应用泛型类型

    本文旨在讲解如何在 React 函数式组件中应用泛型类型,以实现更灵活和可复用的组件。通过具体示例,我们将演示如何将泛型类型传递给组件,并解决在使用 string | number 类型时可能遇到的 TypeScript 错误。同时,我们将提供一些建议,以帮助你编写更健壮的 React 代码。 泛型…

    2025年12月20日
    000
  • 在 React 函数式组件中应用泛型

    本文介绍了如何在 React 函数式组件中使用泛型,以创建更灵活、可复用的组件。通过将类型参数传递给组件,可以使其处理不同类型的数据,避免代码冗余。同时,针对 string | number 联合类型在 useState 中遇到的问题,提供了两种解决方案,帮助开发者更好地掌握 React 类型系统。…

    2025年12月20日
    000
  • js怎么实现字符串反转

    javascript中字符串反转最推荐的方法是split(”).reverse().join(”),1.该方法简洁且可读性强;2.不能直接对字符串使用reverse()是因为字符串具有不可变性,而reverse()是会改变原数组的变异方法;3.性能上for循环通常最优,但日常…

    2025年12月20日
    000
  • JS事件处理怎么实现

    JS事件处理核心是响应用户操作,主要通过三种方式实现:HTML内联绑定、DOM属性绑定和addEventListener。其中,addEventListener最推荐,支持绑定多个函数并控制事件流。事件流包括捕获和冒泡两个阶段:捕获从document向下传递到目标元素,冒泡则从目标元素向上传递至do…

    2025年12月20日
    000
  • js怎样实现树形菜单

    构建树形菜单数据结构的核心是使用嵌套的children属性表达父子关系,每个节点包含唯一id和name,适合递归渲染;2. 交互逻辑包括展开/折叠、节点选中、懒加载、搜索过滤、拖拽排序和右键菜单,需结合事件监听与状态管理;3. 性能优化策略有虚拟化渲染、懒加载、事件委托、批量dom操作、css优化、…

    2025年12月20日 好文分享
    000
  • javascript闭包如何生成加密随机数

    闭包本身不生成加密随机数,而是封装window.crypto.getrandomvalues()这一浏览器底层api,提供安全随机数的访问接口;2. 通过闭包可私有化缓冲区(如uint32array),避免重复创建,提升代码整洁性与性能;3. 闭包封装了调用细节,使开发者能以简洁函数调用获取加密随机…

    2025年12月20日 好文分享
    000
  • js怎么获取表单输入的值

    获取表单输入值的核心方法是通过dom操作定位元素后访问其.value属性;2. 不同表单元素获取值的方式不同:文本类输入直接使用.value,复选框和单选按钮需判断.checked并获取其value,下拉框通过.value获取选中项,多选需遍历收集;3. 表单提交时获取值适合整体校验和数据提交,通过…

    2025年12月20日
    000
  • js 如何使用groupBy对对象数组进行分组

    使用reduce是javascript中对对象数组分组最常用且灵活的方法;1. 通过reduce遍历数组,以目标属性值作为键,将对象归类到累加器(对象或map)中;2. 当累加器为普通对象时,适用于字符串键,若需支持任意类型键则应使用map;3. 社区已推动object.groupby和map.gr…

    2025年12月20日
    000
  • 什么是JIT编译?JIT的工作原理

    JIT编译通过在程序运行时动态编译热点代码为机器码以提升执行效率。程序启动时以解释方式执行,JIT编译器监控运行情况并识别频繁执行的代码段,随后将其编译为机器码并进行优化,如内联函数和循环展开,再用编译后的代码替换原有解释执行的代码,从而加速运行。当运行时假设失效时,支持反优化回退到解释执行。相比A…

    2025年12月20日
    000
  • js 怎样生成UUID字符串

    最直接且推荐的方式是使用crypto.randomuuid(),它基于系统级加密安全随机数生成器,生成符合rfc 4122标准的版本4 uuid,安全、唯一、无需依赖;2. 其次可选用第三方库如uuid npm包,支持多种版本(v1/v3/v4/v5),功能全面、兼容性好,适用于需要特定uuid版本…

    2025年12月20日
    000
  • javascript闭包怎么缓存API响应数据

    闭包能实现api响应数据的缓存,因为它通过内部函数引用外部函数的变量,使这些变量在外部函数执行后仍保留在内存中,不会被垃圾回收;2. 选择闭包缓存的优势在于其私有性和持久性,缓存数据被封装在函数作用域内,仅通过返回的函数访问,避免了全局污染,且每个闭包实例独立,互不干扰;3. 实际应用场景包括缓存用…

    2025年12月20日 好文分享
    000
  • js怎样实现数组随机排序

    javascript实现数组随机排序的推荐方法是使用fisher-yates洗牌算法,1. 首先从数组末尾开始,每次随机选择一个未处理的元素;2. 然后将该元素与当前元素交换;3. 重复此过程直到所有元素都被处理,从而确保每个元素出现在任何位置的概率相等;为避免修改原数组,可先通过扩展运算符或sli…

    2025年12月20日 好文分享
    000
  • JS如何实现广度优先搜索?BFS的应用

    JS实现广度优先搜索(BFS)的核心在于使用队列逐层遍历图或树,结合visited集合避免重复访问,其典型应用包括无权图最短路径、社交网络连接、Web爬虫和迷宫求解,与DFS相比,BFS适合寻找最短路径和层级遍历,而DFS更适合遍历所有路径或处理深度较深的图,优化BFS的方法包括双向BFS、使用优先…

    2025年12月20日
    000
  • 优化React组件渲染:解决hover事件导致的过度重渲染问题

    本文旨在解决React应用中因hover事件处理不当导致的组件过度重渲染问题。通过分析mouseOver和mouseOut事件的触发机制,提出使用mouseEnter和mouseLeave事件替代,并结合React.memo优化组件,从而有效减少不必要的渲染,提升应用性能。 在React应用开发中,…

    2025年12月20日
    000
  • 高频渲染优化:React组件hover事件引发的性能问题与解决方案

    摘要:本文针对React组件在hover事件中出现大量重新渲染导致的性能问题,提供了一种简单有效的解决方案。通过将onMouseOver和onMouseOut事件替换为onMouseEnter和onMouseLeave,可以显著减少不必要的渲染,提升应用性能。 在React开发中,hover事件经常…

    2025年12月20日
    000
  • 优化 React 组件渲染:解决鼠标悬停导致的过度渲染问题

    本文旨在解决 React 应用中因鼠标悬停事件(onMouseOver)触发的过度渲染问题。通过将 onMouseOver 替换为 onMouseEnter,并结合 onMouseOut 替换为 onMouseLeave,可以显著减少不必要的组件重新渲染,提升应用性能,尤其是在处理大量组件时。文章将…

    2025年12月20日
    000
  • JavaScript 中如何过滤对象数组,确保所有指定值都存在于对象的数组属性中

    本文介绍了如何使用 JavaScript 过滤一个对象数组,根据一组过滤器(包含类别和标签)筛选出符合特定条件的对象。类别采用 OR 逻辑,即对象只需匹配任意一个类别即可;标签采用 AND 逻辑,即对象必须匹配所有指定的标签。通过 filter、every 和 some 方法的组合使用,可以高效地实…

    2025年12月20日
    000
  • 使用 JavaScript 过滤对象数组:类别 OR 标签 AND

    本文旨在提供一种使用 JavaScript 过滤对象数组的有效方法,该数组基于类别和标签的组合条件。类别采用 OR 逻辑,即只要对象包含任何一个指定的类别即可;而标签采用 AND 逻辑,即对象必须包含所有指定的标签。我们将提供一个可复用的代码示例,并解释其工作原理,帮助你轻松实现复杂的数据过滤需求。…

    2025年12月20日
    000

发表回复

登录后才能评论
关注微信