首页 > web前端 > js教程 > 正文

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

心靈之曲
发布: 2025-08-17 23:06:01
原创
871人浏览过

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免费学习笔记(深入)”;

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

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

代码示例分析

以下面的代码为例:

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

Promise.resolve('2').then(console.log);

console.log('3');
登录后复制

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

燕雀Logo
燕雀Logo

为用户提供LOGO免费设计在线生成服务

燕雀Logo 101
查看详情 燕雀Logo
  1. setTimeout 被添加到调用栈,然后被推入 WebAPI,并从调用栈中弹出。setTimeout 的回调函数被放入任务队列。
  2. Promise.resolve('2').then(console.log) 被添加到调用栈。Promise.resolve 创建一个已解决的 Promise,其 then 方法的回调函数被放入微任务队列。
  3. console.log('3') 被添加到调用栈并执行,输出 3。
  4. 此时调用栈为空,事件循环检查微任务队列,发现 Promise.then 的回调函数,将其放入调用栈并执行,输出 2。
  5. 微任务队列为空,事件循环从任务队列中取出 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事件循环:任务队列与微任务队列的执行顺序详解的详细内容,更多请关注php中文网其它相关文章!

最佳 Windows 性能的顶级免费优化软件
最佳 Windows 性能的顶级免费优化软件

每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。

下载
来源:php中文网
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
热门推荐
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新 English
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号