讲师中心 微信公众号
AI工具推荐 视频效率加速

深入理解 JavaScript Promise 异步执行顺序与微任务队列

梦磊同学_4576

梦磊同学_4576

发布时间:2025-12-02 14:59:01

|

490人浏览过

|

来源于php中文网

原创

深入理解 JavaScript Promise 异步执行顺序与微任务队列

本文深入探讨 javascript 中 promise 异步函数的执行机制,特别是 `then` 方法如何与微任务队列(promisejob queue)协同工作。通过一个具体代码示例,我们将逐步解析代码执行流程、promise 状态变化以及回调函数入队与出队的时机,揭示 `console.log` 输出顺序背后的原理,帮助开发者掌握 promise 异步行为的精确控制。

JavaScript 异步编程基础与 Promise 机制

JavaScript 是一种单线程语言,这意味着它一次只能执行一个任务。为了处理耗时的操作(如网络请求、文件读写),JavaScript 引入了异步编程机制。Promise 是 ES6 引入的一种处理异步操作的模式,它代表一个异步操作的最终完成(或失败)及其结果值。

理解 Promise 的执行顺序,关键在于把握 JavaScript 的事件循环(Event Loop)、调用栈(Call Stack)、微任务队列(Microtask Queue,也称 PromiseJob Queue)和宏任务队列(Macrotask Queue)的概念。

  • 调用栈 (Call Stack):同步代码执行的地方。当函数被调用时,它被推入栈中;函数返回时,它被弹出。
  • 微任务队列 (Microtask Queue):存放 Promise 的 then/catch/finally 回调函数等。微任务在当前宏任务执行完毕后,且在下一个宏任务开始前,会被清空。
  • 宏任务队列 (Macrotask Queue):存放如 setTimeout、setInterval、I/O 操作等回调。在清空微任务队列后,事件循环会从宏任务队列中取出一个任务执行。

Promise 的核心特性:

  1. Promise.resolve():创建一个已解决(fulfilled)的 Promise,这个操作本身是同步的。
  2. then() 方法
    • 当一个 Promise 被解决(fulfilled)时,其 .then() 中注册的回调函数会被放入微任务队列。
    • then() 方法本身总是返回一个新的 Promise,这个新 Promise 的状态最初是 pending。它的解决或拒绝取决于 then 回调函数的执行结果。即使 then() 是在一个已解决的 Promise 上调用的,它返回的 Promise 仍然是 pending,因为其回调需要异步执行。

示例代码分析

为了更清晰地演示 Promise 的执行顺序,我们使用一个带有命名 Promise 和回调函数的示例代码:

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

var a = Promise.resolve(); // Promise a 立即解决

var b = a.then(function a_then() {
  console.log(1);
  var c = Promise.resolve(); // Promise c 立即解决
  var d = c.then(function c_then() {
    console.log(2);
  });
  var e = d.then(function d_then() {
    console.log(3);
  });
  console.log(4);
});

var f = b.then(function b_then() {
  console.log(5);
  var g = Promise.resolve(); // Promise g 立即解决
  var h = g.then(function g_then() {
    console.log(6);
  });
  var i = h.then(function h_then() {
    console.log(7);
  });
  console.log(8);
});

console.log(9);

我们将逐行分析这段代码的执行流程,并观察 console.log 的输出顺序。

详细执行流程解析

以下是代码执行的详细步骤,关注调用栈、Promise 状态和微任务队列的变化:

阶段一:同步代码执行

  1. var a = Promise.resolve();

    • a 被创建并立即进入 fulfilled 状态。
    • a 的状态: fulfilled。
    • 微任务队列: 空。
  2. var b = a.then(function a_then() { ... });

    • a.then() 被调用。由于 a 已经 fulfilled,a_then 回调函数被添加到微任务队列。
    • b 被创建,状态为 pending。
    • a 的状态: fulfilled;b 的状态: pending。
    • 微任务队列: [a_then]。
  3. var f = b.then(function b_then() { ... });

    • b.then() 被调用。由于 b 仍是 pending 状态,b_then 回调函数在 b 解决后才会被添加。
    • f 被创建,状态为 pending。
    • a 的状态: fulfilled;b 的状态: pending;f 的状态: pending。
    • 微任务队列: [a_then]。
  4. console.log(9);

    • 同步代码执行,输出 9。
    • 输出: 9
    • 微任务队列: [a_then]。

至此,所有同步代码执行完毕。调用栈清空,事件循环开始检查微任务队列。

阶段二:第一次微任务队列处理 (a_then)

  1. 事件循环从微任务队列中取出 a_then 并执行。

    • 微任务队列: 空。
  2. console.log(1); (在 a_then 内部)

    • 输出 1。
    • 输出: 9, 1
  3. var c = Promise.resolve();

    • c 被创建并立即进入 fulfilled 状态。
    • c 的状态: fulfilled。
  4. var d = c.then(function c_then() { ... });

    • c.then() 被调用。由于 c 已经 fulfilled,c_then 回调函数被添加到微任务队列。
    • d 被创建,状态为 pending。
    • 微任务队列: [c_then]。
  5. var e = d.then(function d_then() { ... });

    • d.then() 被调用。由于 d 仍是 pending 状态,d_then 回调函数在 d 解决后才会被添加。
    • e 被创建,状态为 pending。
    • 微任务队列: [c_then]。
  6. console.log(4); (在 a_then 内部)

    • 输出 4。
    • 输出: 9, 1, 4
  7. a_then 函数执行完毕,其返回值(undefined)用于解决 b。

    • b 的状态变为 fulfilled。
    • 由于 b 已经 fulfilled,之前注册在 b.then() 上的 b_then 回调函数现在被添加到微任务队列。
    • 微任务队列: [c_then, b_then]。

阶段三:第二次微任务队列处理 (c_then)

  1. 事件循环从微任务队列中取出 c_then 并执行。

    • 微任务队列: [b_then]。
  2. console.log(2); (在 c_then 内部)

    Alibabacloud Sdk Client Initialization For Java
    Alibabacloud Sdk Client Initialization For Java

    在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。

    下载
    • 输出 2。
    • 输出: 9, 1, 4, 2
  3. c_then 函数执行完毕,其返回值(undefined)用于解决 d。

    • d 的状态变为 fulfilled。
    • 由于 d 已经 fulfilled,之前注册在 d.then() 上的 d_then 回调函数现在被添加到微任务队列。
    • 微任务队列: [b_then, d_then]。

阶段四:第三次微任务队列处理 (b_then)

  1. 事件循环从微任务队列中取出 b_then 并执行。

    • 微任务队列: [d_then]。
  2. console.log(5); (在 b_then 内部)

    • 输出 5。
    • 输出: 9, 1, 4, 2, 5
  3. var g = Promise.resolve();

    • g 被创建并立即进入 fulfilled 状态。
    • g 的状态: fulfilled。
  4. var h = g.then(function g_then() { ... });

    • g.then() 被调用。由于 g 已经 fulfilled,g_then 回调函数被添加到微任务队列。
    • h 被创建,状态为 pending。
    • 微任务队列: [d_then, g_then]。
  5. var i = h.then(function h_then() { ... });

    • h.then() 被调用。由于 h 仍是 pending 状态,h_then 回调函数在 h 解决后才会被添加。
    • i 被创建,状态为 pending。
    • 微任务队列: [d_then, g_then]。
  6. console.log(8); (在 b_then 内部)

    • 输出 8。
    • 输出: 9, 1, 4, 2, 5, 8
  7. b_then 函数执行完毕,其返回值(undefined)用于解决 f。

    • f 的状态变为 fulfilled。
    • 微任务队列: [d_then, g_then]。

阶段五:第四次微任务队列处理 (d_then)

  1. 事件循环从微任务队列中取出 d_then 并执行。

    • 微任务队列: [g_then]。
  2. console.log(3); (在 d_then 内部)

    • 输出 3。
    • 输出: 9, 1, 4, 2, 5, 8, 3
  3. d_then 函数执行完毕,其返回值(undefined)用于解决 e。

    • e 的状态变为 fulfilled。
    • 微任务队列: [g_then]。

阶段六:第五次微任务队列处理 (g_then)

  1. 事件循环从微任务队列中取出 g_then 并执行。

    • 微任务队列: 空。
  2. console.log(6); (在 g_then 内部)

    • 输出 6。
    • 输出: 9, 1, 4, 2, 5, 8, 3, 6
  3. g_then 函数执行完毕,其返回值(undefined)用于解决 h。

    • h 的状态变为 fulfilled。
    • 由于 h 已经 fulfilled,之前注册在 h.then() 上的 h_then 回调函数现在被添加到微任务队列。
    • 微任务队列: [h_then]。

阶段七:第六次微任务队列处理 (h_then)

  1. 事件循环从微任务队列中取出 h_then 并执行。

    • 微任务队列: 空。
  2. console.log(7); (在 h_then 内部)

    • 输出 7。
    • 输出: 9, 1, 4, 2, 5, 8, 3, 6, 7
  3. h_then 函数执行完毕,其返回值(undefined)用于解决 i。

    • i 的状态变为 fulfilled。
    • 微任务队列: 空。

最终输出顺序为:9, 1, 4, 2, 5, 8, 3, 6, 7。

注意事项与总结

  1. 同步优先原则:JavaScript 总是优先执行所有同步代码。只有当调用栈清空后,事件循环才会检查微任务队列。
  2. 微任务队列的优先级:微任务队列在每个宏任务(包括主脚本的执行)结束后立即清空。这意味着在一个宏任务内部产生的微任务,会在当前宏任务结束,但下一个宏任务开始之前被执行。
  3. then() 返回的新 Promise 总是 pending:理解 then() 方法返回的 Promise 总是从 pending 状态开始非常重要。它的最终状态取决于其回调函数的执行结果,而回调函数是异步执行的。
  4. Promise 链式调用:当一个 Promise 解决后,其 .then() 回调会被加入微任务队列。如果这个回调内部又返回了一个 Promise,那么下一个 .then() 的回调会等待这个内部 Promise 解决后才会被加入微任务队列。
  5. Promise.resolve() 的同步性:Promise.resolve() 本身是同步的,它会立即创建一个已解决的 Promise。但是,对这个 Promise 调用 .then() 所注册的回调,仍然是异步的,会被放入微任务队列。

通过以上详细的步骤分析,我们可以清晰地看到 JavaScript Promise 异步机制的内部工作原理,特别是微任务队列在调度 Promise 回调中的核心作用。掌握这些概念对于编写健壮、可预测的异步 JavaScript 代码至关重要。

热门AI工具

更多
二狗PPT
二狗PPT Hot

一款AI演示文稿工具,主要用于专为中式职场打造的AI PPT生成工具,适合需要提升相关任务效率的用户。

UpDream
UpDream Hot

一款AI视频创作工具,主要用于哔哩哔哩推出的自研AI视频创作工具,适合需要提升相关任务效率的用户。

蛙蛙写作

一款AI论文写作工具,主要用于超级AI智能写作助手,适合需要提升相关任务效率的用户。

DeepSeek

DeepSeek是一款面向对话、写作、编程和推理场景的AI大模型工具。

讯飞智作

讯飞智作是一款AI视频创作工具,AI文本配音工具,数字人课程、营销视频制作。

Atoms
Atoms Hot

Atoms是一款AI智能体工具,第一支自动构建真实业务的 AI 团队。

WorkBuddy

一款AI办公效率工具,主要用于腾讯云推出的AI原生桌面智能体工作台,适合需要提升相关任务效率的用户。

Loomy
Loomy Hot

一款AI工具,主要用于科大讯飞发布的桌面级 AI 助理,比 OpenClaw 更易用、更安全!,适合需要提升相关任务效率的用户。

豆包大模型

豆包大模型是一款由字节跳动推出的企业级大语言模型服务平台。

相关专题

更多
es6新特性
es6新特性

es6新特性有:1、块级作用域变量;2、箭头函数;3、模板字符串;4、解构赋值;5、默认参数;6、 扩展运算符;7、 类和继承;8、Promise。本专题为大家提供es6新特性的相关的文章、下载、课程内容,供大家免费下载体验。

265

2023.07.17

es6新特性有哪些
es6新特性有哪些

es6的新特性有:1、块级作用域;2、箭头函数;3、解构赋值;4、默认参数;5、扩展运算符;6、模板字符串;7、类和模块;8、迭代器和生成器;9、Promise对象;10、模块化导入和导出等等。本专题为大家提供es6新特性的相关的文章、下载、课程内容,供大家免费下载体验。

386

2023.08.04

JavaScript ES6新特性
JavaScript ES6新特性

ES6是JavaScript的根本性升级,引入let/const实现块级作用域、箭头函数解决this绑定问题、解构赋值与模板字符串简化数据处理、对象简写与模块化提升代码可读性与组织性。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

335

2025.12.24

堆和栈的区别
堆和栈的区别

堆和栈的区别:1、内存分配方式不同;2、大小不同;3、数据访问方式不同;4、数据的生命周期。本专题为大家提供堆和栈的区别的相关的文章、下载、课程内容,供大家免费下载体验。

4527

2023.07.18

堆和栈区别
堆和栈区别

堆(Heap)和栈(Stack)是计算机中两种常见的内存分配机制。它们在内存管理的方式、分配方式以及使用场景上有很大的区别。本文将详细介绍堆和栈的特点、区别以及各自的使用场景。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

2068

2023.08.10

线程和进程的区别
线程和进程的区别

线程和进程的区别:线程是进程的一部分,用于实现并发和并行操作,而线程共享进程的资源,通信更方便快捷,切换开销较小。本专题为大家提供线程和进程区别相关的各种文章、以及下载和课程。

3458

2023.08.10

console接口是干嘛的
console接口是干嘛的

console接口是一种用于在计算机命令行或浏览器开发工具中输出信息的工具,提供了一种简单的方式来记录和查看应用程序的输出结果和调试信息。本专题为大家提供console接口相关的各种文章、以及下载和课程。

776

2023.08.08

console.log是什么
console.log是什么

console.log 是 javascript 函数,用于在浏览器控制台中输出信息,便于调试和故障排除。想了解更多console.log的相关内容,可以阅读本专题下面的文章。

5243

2024.05.29

Buffalo框架零基础入门教程
Buffalo框架零基础入门教程

本专题整理Buffalo框架入门内容,涵盖Go环境准备、buffalo CLI安装、新项目生成、目录结构说明、dev热加载启动、数据库连接配置与常见报错排查,帮助新手按约定优于配置的思路跑通第一个Buffalo框架应用。

0

2026.09.23

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
WebStorm 官方调试文档
WebStorm 官方调试文档

共0课时 | 0人学习

React 教程
React 教程

共58课时 | 11.9万人学习

TypeScript 教程
TypeScript 教程

共19课时 | 6.5万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn