如何让JavaScript调用栈等待异步函数执行完成后再执行后续代码?
问题根源
两份代码的问题分为核心逻辑错误和语法错误两类:
- 核心逻辑错误:
first函数返回的Promise和内部的setTimeout完全没有绑定关系。调用setTimeout只是同步完成定时宏任务的注册动作,注册完成后代码会立刻向下执行,将返回的Promise置为已敲定状态,不会等待1秒/2秒后的打印逻辑执行。无论是.then链式调用还是await,都只会等待显式绑定的Promise状态变更,不会主动追踪函数内部游离的异步任务。 - Promise写法的语法错误:
.then(second())会在执行到then的瞬间同步调用second(),把执行结果(undefined)作为参数传入then,正确写法是传入函数引用.then(second),否则即使Promise时序正确,second也会提前执行。 - async/await写法的逻辑错误:
async函数执行到return true时就会立刻将返回的Promise标记为fulfilled状态,此时setTimeout的回调还在宏任务队列中等待计时结束,await拿到敲定状态后会立刻执行后续的second,导致顺序错乱。
修正方案
核心调整思路:让first返回的Promise,在setTimeout回调执行完成、打印出数字1之后再变更为已敲定状态,后续的second就会等待1打印完成后再执行。
修正后的Promise链式调用版本
function first(){ // 自定义Promise,包裹setTimeout逻辑 return new Promise((resolve) => { setTimeout( () => { console.log(1) // 打印1完成后再resolve,通知下游任务可以执行 resolve(true) }, 1000 ) }) } function second(){ console.log(2) } function a(){ first() // 传入函数引用,不要直接加括号调用second .then(second) } console.log("running...") a()
修正后的async/await版本
// first直接返回Promise即可,不需要额外标记async function first(){ return new Promise((resolve) => { setTimeout( () => { console.log(1) // 打印1完成后再resolve resolve(true) }, 2000 ) }) } function second(){ console.log(2) } async function a(){ await first() second() } console.log("running...") a()
两份代码执行后都会先打印running...,等待对应定时时长后打印1,紧接着打印2,和预期输出一致。
内容的提问来源于stack exchange,提问作者user16929274
相关产品推荐
相关产品推荐

