为何async函数在第二个.then()前执行?JS Promise执行顺序解析
同一Promise的await回调为何先于后续then回调执行?
核心原因很直接:你代码里的第二个then并不是绑定在原始的newPromise上,而是绑定在第一个then返回的新Promise上。而await newPromise是直接绑定在原始newPromise上的回调,微任务队列的执行顺序规则导致了await的输出先于第二个then的输出。
下面一步步拆解事件循环的完整执行流程:
全局代码执行阶段
- 初始化变量
a,创建newPromise时立刻执行executor函数:里面的setTimeout被扔进宏任务队列,等待1秒后触发。 - 调用
newPromise.then(...):给原始Promise注册第一个回调(记为回调A),这个then会返回一个新的Promise(记为PromiseB)。接着调用PromiseB.then(...),给PromiseB注册第二个回调(记为回调B)。 - 执行立即执行的async函数:遇到
await newPromise,相当于给原始newPromise注册了另一个回调(记为回调C)——当newPromiseresolve后,回调C会把console.log(res+ " from async await")放进微任务队列。
1秒后宏任务执行阶段
setTimeout的回调触发:
- 打印
Async Task,调用resolve(a),原始newPromise变为resolved状态。 - 此时,所有绑定在原始
newPromise上的回调会按注册顺序依次加入微任务队列:先回调A,再回调C。
微任务队列执行阶段
事件循环会清空当前微任务队列后才会处理其他任务:
- 执行
回调A:打印Async resolved Hanzala,返回data.toUpperCase()(即HANZALA)。这个返回值会让PromiseB变为resolved状态,于是回调B被加入微任务队列。 - 执行
回调C:打印Hanzala from async await。 - 微任务队列里此时还有刚加入的
回调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
相关产品推荐
相关产品推荐

