Node.js Async/await控制流解析:含setTimeout的异步流程示例
解析Node.js中Async/Await结合setTimeout的异步控制流执行逻辑
先来看看这段代码的完整实现:
function delayPromise(item){ return new Promise(resolve=>setTimeout(resolve, 1000)); } async function delay(item){ await delayPromise(item); console.log(item); } async function test(){ var arr = [1,2, 3,4, 5, 6]; for(elem of arr){ console.log('starting ' + elem); await delay(elem); } console.log('done'); } test();
接下来我们一步步拆解它的执行逻辑,搞清楚为什么会输出顺序的starting X + X:
1. 基础函数的作用
delayPromise:这是一个简单的延迟工具,返回一个Promise对象,1000ms(1秒)后会调用resolve,标记这个Promise为已完成状态。delay:标记为async的函数,它会先等待delayPromise的Promise完成,然后再打印传入的item。test:核心的控制流函数,负责遍历数组并依次处理每个元素。
2. 核心执行流程(从调用test()开始)
当你调用test()时,因为它是async函数,会立刻启动执行,但遇到await时会暂停,直到等待的Promise完成:
- 首先创建数组
[1,2,3,4,5,6],进入for...of循环,第一个元素是1:- 先同步执行
console.log('starting 1'),输出starting 1。 - 接着调用
delay(1),进入这个async函数后,执行到await delayPromise(1):- 此时
delay函数会暂停执行,把控制权交回给test函数;而test函数遇到await,也会暂停自己的执行,等待delay(1)返回的Promise完成。 - 与此同时,
delayPromise(1)里的setTimeout被加入Node.js的宏任务队列,开始倒计时1秒。
- 此时
- 先同步执行
- 1秒后,
setTimeout的回调触发,调用resolve,标记delayPromise(1)的Promise为已完成:- 这时
delay函数会恢复执行,执行console.log(1),输出1,然后delay函数执行完毕,返回一个已完成的Promise。 test函数的await等待结束,恢复执行,进入下一次循环,处理元素2:重复上面的「打印starting → 等待1秒 → 打印元素」流程。
- 这时
- 就这样,数组里的每个元素都会串行处理:上一个元素的1秒延迟完全结束后,才会开始处理下一个元素,最终就会得到你看到的顺序输出。
3. 为什么不是同时触发所有延迟?
关键点在于for...of循环里的await delay(elem)——每次迭代都等待当前的异步操作完成才会进入下一轮。如果这里没有await,所有的setTimeout会被同时加入宏任务队列,1秒后所有元素会一起打印,但因为有了await,我们把原本可以并行的异步操作强制改成了串行执行,这也是Async/Await用来控制异步流程的常见用法。
内容的提问来源于stack exchange,提问作者errorMessage
相关产品推荐
相关产品推荐

