自定义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 });
关键思路解释
- 统一转为Promise:用
arr.map(item => Promise.resolve(item))把所有输入(包括非Promise值)转为Promise,确保处理逻辑统一。 - 追踪完成状态:用
remaining变量记录还未完成的Promise数量,每次有一个Promise完成就减1,当remaining变为0时,当前的结果就是最后一个完成的。 - 返回新Promise:整个
Promise.last返回一个新的Promise,外部可以通过then获取最后一个完成的结果,符合Promise API的设计习惯。
如果你希望返回的是最后完成的那个Promise实例而不是结果,只需要稍微调整:把lastResult改为存储对应的Promise实例即可,不过通常场景下我们更关注最后完成的结果。
内容的提问来源于stack exchange,提问作者Alexey_js
相关产品推荐
相关产品推荐

