You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何async函数在第二个.then()前执行?JS Promise执行顺序解析

同一Promise的await回调为何先于后续then回调执行?

核心原因很直接:你代码里的第二个then并不是绑定在原始的newPromise上,而是绑定在第一个then返回的新Promise上。而await newPromise是直接绑定在原始newPromise上的回调,微任务队列的执行顺序规则导致了await的输出先于第二个then的输出。

下面一步步拆解事件循环的完整执行流程:

全局代码执行阶段

  1. 初始化变量a,创建newPromise时立刻执行executor函数:里面的setTimeout被扔进宏任务队列,等待1秒后触发。
  2. 调用newPromise.then(...):给原始Promise注册第一个回调(记为回调A),这个then会返回一个新的Promise(记为PromiseB)。接着调用PromiseB.then(...),给PromiseB注册第二个回调(记为回调B)。
  3. 执行立即执行的async函数:遇到await newPromise,相当于给原始newPromise注册了另一个回调(记为回调C)——当newPromiseresolve后,回调C会把console.log(res+ " from async await")放进微任务队列。

1秒后宏任务执行阶段

setTimeout的回调触发:

  1. 打印Async Task,调用resolve(a),原始newPromise变为resolved状态。
  2. 此时,所有绑定在原始newPromise上的回调会按注册顺序依次加入微任务队列:先回调A,再回调C。

微任务队列执行阶段

事件循环会清空当前微任务队列后才会处理其他任务:

  1. 执行回调A:打印Async resolved Hanzala,返回data.toUpperCase()(即HANZALA)。这个返回值会让PromiseB变为resolved状态,于是回调B被加入微任务队列。
  2. 执行回调C:打印Hanzala from async await。
  3. 微任务队列里此时还有刚加入的回调B,执行它:打印HANZALA from second then。

这就是实际输出顺序的由来——回调B是在回调A执行完之后才被加入微任务队列的,自然排在回调C之后执行。

补充:如何得到你预期的输出?

如果想让HANZALA from second then先于Hanzala from async await输出,只需把await的回调绑定在PromiseB上,而非原始的newPromise:

(async () => {
    try {
        const res = await newPromise
            .then(data => {
                console.log("Async resolved",data)
                return data.toUpperCase()
            })
        console.log(res+ " from async await")
    } catch (error) {
        console.log(error+"Error form async");
    }
})();

这样await的回调会和回调B一起绑定在PromiseB上,当PromiseBresolve时,两个回调会按注册顺序加入微任务队列,就能得到你预期的输出顺序。

内容的提问来源于stack exchange,提问作者Hanzala Sarguroh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 21:54:57