为何用setTimeout包装Promise无法按预期顺序执行?
问题分析与解决
问题原因
你这里的核心问题是调用map时就已经启动了所有Promise的异步操作:
当执行testArray.map(async (value) => ...)时,数组中的每一项会立刻执行对应的async函数,每个函数里的setTimeout(resolve, 2000)会同时触发——相当于5个2秒定时器同时开始计时。等2秒后,所有test()会一同执行,自然日志会同时输出。
后续的reduce只是按顺序等待这些已经在并行运行的Promise完成,但无法改变它们早已启动的事实,所以达不到顺序执行的效果。
正确实现方式
要实现每隔2秒打印一条日志,需要确保前一个异步操作完成后,再启动下一个。推荐两种写法:
写法1:用reduce直接构建顺序Promise链
const testArray = [1, 2, 3, 4, 5]; const test = async () => { console.log("Testing console log: ", new Date()); }; // 每次迭代都在前一个Promise完成后,才创建并启动新的异步操作 const testResult = testArray.reduce((prevPromise) => { return prevPromise.then(() => { return new Promise(resolve => setTimeout(resolve, 2000)).then(test); }); }, Promise.resolve());
写法2:用for...of循环(更直观)
const testArray = [1, 2, 3, 4, 5]; const test = async () => { console.log("Testing console log: ", new Date()); }; const runSequentially = async () => { for (const _ of testArray) { await new Promise(resolve => setTimeout(resolve, 2000)); await test(); } }; runSequentially();
这两种写法都会确保:前一个2秒的定时器完成后,才执行test()并启动下一个定时器,最终实现每隔2秒打印一条日志的效果。
内容的提问来源于stack exchange,提问作者Jaeho Lee
相关产品推荐
相关产品推荐

