我自行实现的Promise.all()方法存在什么问题?
问题分析
- 对非Promise类型值直接调用
then方法会报错。当输入数组的元素不是Promise实例时,你的代码在单独调用Promise.resolve(promise).then(...)之后,还会执行promise.then(...),而普通值(比如示例里的数字1337)本身不存在then方法,会直接抛出类型错误,这是代码运行失败的核心原因。 - 返回结果顺序不符合原生
Promise.all规范。你通过push方法向结果数组追加值,最终结果顺序由各个Promise的resolve时间决定,而原生Promise.all的返回结果顺序和输入数组的顺序完全一致,和resolve先后无关。 - 非Promise元素的逻辑分支重复处理。如果不存在调用
then报错的问题,非Promise元素会被两个then分别往结果数组里添加两次值,导致最终结果数组长度超过输入数组长度,永远无法满足resolved === promises.length的判断条件。
修复后的代码
const promiseAll = promises => new Promise((resolve, reject) => { if (promises.length === 0) return resolve([]); const results = new Array(promises.length); let resolvedCount = 0; promises.forEach((item, index) => { // 统一把所有元素转成Promise处理,不需要单独判断类型 Promise.resolve(item).then( value => { results[index] = value; resolvedCount++; if (resolvedCount === promises.length) { resolve(results); } }, err => reject(err) ) }) })
修复说明
- 所有输入元素统一用
Promise.resolve()包裹,不管是不是Promise实例都会被转成标准Promise处理,避免了类型判断的逻辑漏洞,也不会出现普通值调用then报错的问题。 - 结果数组初始化时就指定和输入数组相同的长度,通过索引赋值保证结果顺序和输入顺序完全一致,符合原生
Promise.all的行为。 - 每个元素只绑定一次
then回调,不会出现重复添加结果的问题。
内容的提问来源于stack exchange,提问作者BERTOLDO
相关产品推荐
相关产品推荐

