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

ES5实现JS循环中Promise无论成败均串行调用同一函数

用ES5语法实现Promise串行调用(无论成功/失败都继续)

你原来的写法有两个核心问题:

  • var的变量提升导致i的值异常:var声明的变量是函数级作用域,循环里所有的i指向同一个引用。当setTimeout触发时,循环早已结束,i会变成5,最终调用的都是myFunction(5)。
  • 没有实现串行执行:循环里直接调用myFunction(i)会让所有Promise同时启动,是并行而非串行的逻辑。

下面用两种ES5兼容的方式解决这个问题:


方法1:构建Promise链式调用

我们可以先初始化一个已决议的Promise作为起点,然后通过循环依次把每个myFunction的调用挂载到链上。不管上一个Promise是resolve还是reject,都继续执行下一个任务。

function myFunction(i) {
  return new Promise(function(resolve, reject) {
    setTimeout(function() {
      console.log(i);
      // 可模拟失败场景:比如i===2时触发reject
      // if(i === 2) reject(new Error('Test error at ' + i));
      resolve(i);
    }, i * 1000);
  });
}

// 初始化一个已resolve的Promise作为链式调用的起点
var promiseChain = Promise.resolve();

// 循环构建串行链
for (var i = 0; i < 5; i++) {
  // 用立即执行函数(IIFE)保存当前i的快照,避免变量提升问题
  (function(currentI) {
    promiseChain = promiseChain
      .then(function() {
        return myFunction(currentI);
      })
      .catch(function(err) {
        // 可选:在这里处理错误,比如打印错误信息
        console.error('Error occurred:', err);
        // 无论失败与否,都继续执行下一个任务
        return myFunction(currentI);
      });
  })(i);
}

关键细节:

  • 立即执行函数创建了独立的作用域,把当前循环的i值保存为currentI,避免后续循环修改导致的变量污染。
  • 每次循环都会更新promiseChain,将下一个任务挂载到链的末尾,确保任务按顺序串行执行。

方法2:递归调用(更直观的串行逻辑)

如果觉得链式调用不够直观,递归是另一种清晰的实现方式:每次完成当前任务后,再递归调用下一个任务。

function myFunction(i) {
  return new Promise(function(resolve, reject) {
    setTimeout(function() {
      console.log(i);
      // 可模拟失败场景:比如i===3时触发reject
      // if(i === 3) reject(new Error('Failed at index ' + i));
      resolve(i);
    }, i * 1000);
  });
}

function serialCall(currentIndex) {
  // 递归终止条件:所有任务执行完成
  if (currentIndex >= 5) {
    return Promise.resolve();
  }
  
  return myFunction(currentIndex)
    .then(function() {
      // 成功后继续执行下一个任务
      return serialCall(currentIndex + 1);
    })
    .catch(function(err) {
      // 失败后打印错误,仍继续执行下一个任务
      console.error('Error at index ' + currentIndex + ': ', err);
      return serialCall(currentIndex + 1);
    });
}

// 启动串行调用
serialCall(0);

关键细节:

  • serialCall函数负责单个索引的任务执行,完成后递归调用下一个索引,天然保证串行顺序。
  • 无需处理var的变量提升问题,因为每次递归的currentIndex都是独立的函数参数。

两种方法都能满足你的需求:每次循环迭代串行调用myFunction,无论前一个Promise成功还是失败,都继续执行下一个任务,你可以根据习惯选择适合的实现方式。

内容的提问来源于stack exchange,提问作者Akash khan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.08 22:53:14