如何实现支持任意可迭代对象的自定义Promise.all方法
支持可迭代对象的Promise.all实现方案
核心改造要点
- 替换原有依赖
length属性的下标循环,改用for...of遍历所有实现了Symbol.iterator的可迭代对象 - 新增计数器统计总迭代项数、已兑现Promise数量,不再依赖入参的
length属性 - 按迭代顺序为结果数组预留位置,修复原有
push逻辑导致的输出顺序和输入顺序不一致的问题(不符合原生Promise.all规范)
完整实现代码
Promise.all = function (iterable) { // 可迭代对象校验,对齐原生报错格式 if (typeof iterable[Symbol.iterator] !== 'function') { throw new TypeError(`${typeof iterable} ${iterable} is not iterable`) } return new Promise((resolve, reject) => { try { const resultArray = [] let totalCount = 0 // 记录总迭代项数 let resolvedCount = 0 // 记录已兑现的Promise数量 // for...of 天然支持所有可迭代对象,无需关注入参类型 for (const item of iterable) { const currentIndex = totalCount totalCount++ // 用Promise.resolve包装所有项,兼容非Promise类型的入参 Promise.resolve(item).then(data => { // 按迭代顺序存结果,不受Promise兑现快慢影响 resultArray[currentIndex] = data resolvedCount++ // 所有项全部兑现后返回结果 if (resolvedCount === totalCount) { resolve(resultArray) } }, reject) // 任意项reject直接触发整体reject } // 处理空可迭代对象场景,同步返回空数组,对齐原生行为 if (totalCount === 0) { resolve(resultArray) } } catch (e) { reject(e) } }) }
效果验证
你提供的Map测试用例可以正常运行,输出顺序和迭代顺序完全一致:
function resolveTimeout(value, delay) { return new Promise((resolve) => setTimeout(resolve, delay, value)) } const requests = new Map() requests.set('reqA', resolveTimeout(['potatoes', 'tomatoes'], 1000)) requests.set('reqB', resolveTimeout(['oranges', 'apples'], 100)) Promise.all(requests.values()).then(console.log); // 输出:[ ['potatoes', 'tomatoes'], ['oranges', 'apples'] ]
内容的提问来源于stack exchange,提问作者Joji
相关产品推荐
相关产品推荐

