You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何不使用async/await在循环中实现带延迟的Promise串行执行

问题描述

我编写了一个名为printLetters()的函数,预期实现间隔1000ms逐个打印字母的效果,但实际运行时所有字母会在1000ms后同时打印输出。将该函数改写为async异步函数后可正常实现逐字延迟打印的效果,请问如何在不使用async/await语法的前提下,让printLetters()在循环中按延迟逐个resolve Promise,实现间隔打印的预期效果?

问题复现代码

const printLetters = (l) => {
  for (let i = 0; i < l.length; i++) {
    delay(1000).then(() => {
      console.log(l[i]);
      })
  }
}

const printLettersAsync = async(l) => {
   for (let i = 0; i < l.length; i++) {
    await delay(1000);
    console.log(l[i]);
      
  }
}

const delay = (t) => {
  return new Promise(res => setTimeout(res, t))
}

const arr = ['a','b','c']

printLetters(arr)
printLettersAsync(arr)

问题原因

原始printLetters()不符合预期的核心逻辑问题:

  • for循环是同步执行的,会在极短时间内完成所有迭代,一次性注册3个等待1000ms的延时任务
  • 3个定时器几乎同时启动,1000ms到期后同步触发回调,就会一次性输出所有字母
  • async/await版本能正常工作,本质是每次循环都会等待上一个延时Promise执行完成,才会启动下一个定时器,天然保证了执行顺序

无async/await的实现方案

不需要使用async/await语法,只需要通过Promise链式调用,保证下一次延时在上一次打印完成后再启动即可,有两种通用实现:

方案1:循环维护Promise链

初始化一个立即完成的Promise作为链头,每次循环都把下一轮的延时、打印逻辑挂到上一个Promise的.then()回调中,保证顺序执行:

const printLetters = (l) => {
  // 初始化立即resolve的Promise作为执行链起点
  let taskChain = Promise.resolve();
  for (let i = 0; i < l.length; i++) {
    taskChain = taskChain
      .then(() => delay(1000))
      .then(() => {
        console.log(l[i]);
      })
  }
  return taskChain;
}

方案2:递归顺序执行

用递归替代循环,每次打印完当前位置的字母后,再递归调用函数处理下一个索引的内容,终止条件为所有字母打印完成:

const printLetters = (l, currentIndex = 0) => {
  // 递归终止:所有字符处理完成
  if (currentIndex >= l.length) return Promise.resolve();
  return delay(1000)
    .then(() => {
      console.log(l[currentIndex]);
      // 处理下一个字符
      return printLetters(l, currentIndex + 1);
    })
}

以上两种实现的运行效果和async/await版本完全一致:首字母在1000ms后打印,之后每间隔1000ms输出下一个字母,不会出现同时打印的问题,调用方式和原函数完全一致,直接执行printLetters(arr)即可。

内容的提问来源于stack exchange,提问作者D Park

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.09 16:15:42