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

自定义Promise.last API异常求助:已决议Promise未删除反而异常倍增

问题分析与修复方案

首先,咱们来拆解你代码里的几个核心问题:

  • 同步循环 + 异步回调的冲突:你写的for循环是同步执行的,会一次性触发多轮Promise.race(arr),但then里修改arr的操作是异步的——这意味着每一轮race用的都是原始数组,根本没等到之前的then修改数组,自然会出现重复处理、异常倍增的情况。
  • 返回值错误:你最后返回的是arr数组,但Promise.last应该返回一个新的Promise,它会在所有输入Promise中最后一个完成时,resolve其结果。
  • 未处理非Promise值:你的输入数组里有22这种非Promise值,需要先把所有输入都转为Promise,不然Promise.race会直接把它当作已决议的Promise处理。

修复后的代码

function remove(array, index) {
  return array.slice(0, index).concat(array.slice(index + 1));
}

Promise.last = function(arr) {
  // 先把所有元素转为Promise,处理非Promise值
  const promises = arr.map(item => Promise.resolve(item));
  // 用一个变量追踪剩余的Promise数量
  let remaining = promises.length;
  // 存储最后一个完成的结果
  let lastResult;

  // 返回一个新的Promise,当所有都完成时resolve最后一个结果
  return new Promise((resolve) => {
    promises.forEach((promise) => {
      promise.then((res) => {
        lastResult = res;
        remaining--;
        // 当剩余数量为0时,说明这是最后一个完成的
        if (remaining === 0) {
          resolve(lastResult);
        }
      }).catch((err) => {
        // 如果需要处理reject的情况,可以在这里补充逻辑
        // 比如如果有Promise reject,是否直接reject整个last?根据需求调整
        lastResult = err;
        remaining--;
        if (remaining === 0) {
          resolve(lastResult);
        }
      });
    });
  });
};

const promise1 = new Promise((resolve) => setTimeout(resolve, 100, "firstpromise"));
const promise2 = new Promise((resolve) => setTimeout(resolve, 2000, 'secondpromise'));
const promise3 = new Promise((resolve) => setTimeout(resolve, 3000, 'thirdpromise'));

// 调用方式,需要用then获取结果
Promise.last([promise1, promise2, promise3, 22]).then(result => {
  console.log(result); // 输出: thirdpromise
});

关键思路解释

  1. 统一转为Promise:用arr.map(item => Promise.resolve(item))把所有输入(包括非Promise值)转为Promise,确保处理逻辑统一。
  2. 追踪完成状态:用remaining变量记录还未完成的Promise数量,每次有一个Promise完成就减1,当remaining变为0时,当前的结果就是最后一个完成的。
  3. 返回新Promise:整个Promise.last返回一个新的Promise,外部可以通过then获取最后一个完成的结果,符合Promise API的设计习惯。

如果你希望返回的是最后完成的那个Promise实例而不是结果,只需要稍微调整:把lastResult改为存储对应的Promise实例即可,不过通常场景下我们更关注最后完成的结果。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 13:58:10