Async与多Await调用:调用栈挂起及Promise执行时序疑问
Promise并行执行与async/await的执行逻辑误区解析
问题描述
在使用Promise和async函数时,我了解到async函数内部遇到await时,JS引擎会挂起当前调用栈的函数调用,等待被await的Promise resolve。但运行以下代码后发现结果和预期不符:
const pr = new Promise((res, rej) => { setTimeout(() => { res("promise Execution done") }, 5000); }); const pr2 = new Promise((res, rej) => { setTimeout(() => { res("promise Execution done222222") }, 10000); }); async function handelPr() { const val1 = await pr; console.log("Hello"); console.log(val1); const val2 = await pr2; console.log("Hello-->"); console.log(val2); } handelPr()
实际运行总耗时10秒:pr在5秒后resolve,pr2再过5秒后resolve。但我预期pr resolve后pr2才开始执行,总耗时应为15秒;若将pr的延时改为10秒、pr2改为5秒,总耗时仍为10秒。请问这些Promise是否在并行执行?还是我对事件循环的理解存在误区?
问题解答
你的核心误区在于Promise的执行时机:当你通过new Promise()创建实例时,传入的executor函数(即(res, rej) => {...}的回调)会立即同步执行,并非等到await时才启动内部的异步操作。
具体执行流程拆解
脚本一开始运行,
pr和pr2的Promise实例就被创建了:pr内部的setTimeout立刻开始计时(5秒后触发resolve)pr2内部的setTimeout也立刻开始计时(10秒后触发resolve)
这两个定时器是同时启动的,和后续的handelPr调用、await逻辑完全无关。
调用
handelPr后的执行:- 第一个
await pr等待5秒,此时pr2的定时器已经运行了5秒,剩余5秒就会resolve,所以总耗时等于pr2的定时器时长10秒。 - 如果把
pr的延时改为10秒、pr2改为5秒,pr2的定时器在第5秒就已经resolve了,但await pr需要等10秒,等prresolve后,await pr2会直接拿到已resolve的结果,所以总耗时还是10秒。
- 第一个
如何实现预期的串行执行?
要让pr2在prresolve后才启动,需要把pr2的创建放到await pr之后,这样它的executor函数才会在prresolve后才执行,内部的定时器才会开始计时:
async function handelPr() { // 先创建pr并等待其resolve const pr = new Promise((res, rej) => { setTimeout(() => { res("promise Execution done") }, 5000); }); const val1 = await pr; console.log("Hello"); console.log(val1); // pr resolve后再创建pr2,启动其内部定时器 const pr2 = new Promise((res, rej) => { setTimeout(() => { res("promise Execution done222222") }, 10000); }); const val2 = await pr2; console.log("Hello-->"); console.log(val2); } handelPr()
此时总耗时就是5秒+10秒=15秒,符合你最初的预期。
关键结论
- Promise的executor函数是同步执行的,创建实例时就会触发内部的异步操作(比如
setTimeout)。 await的作用只是暂停当前async函数的执行,等待已存在的Promise状态变更,不会控制Promise内部异步操作的启动时机。- 要实现异步操作的串行执行,需将后续Promise的创建放在前一个
await之后。
内容的提问来源于stack exchange,提问作者Manthan Sharma
相关产品推荐
相关产品推荐

