【发布时间】:2021-11-30 14:02:03
【问题描述】:
我正在尝试实施我自己的Promise.all 来准备我的面试。
我的第一个版本是这个
Promise.all = function(promiseArray) {
return new Promise((resolve, reject) => {
try {
let resultArray = []
const length = promiseArray.length
for (let i = 0; i <length; i++) {
promiseArray[i].then(data => {
resultArray.push(data)
if (resultArray.length === length) {
resolve(resultArray)
}
}, reject)
}
}
catch(e) {
reject(e)
}
})
}
但是,本机 Promise.all 不仅接受数组,还接受任何可迭代对象,这意味着任何具有 Symbol.iterator 的对象,例如数组、Set 或 Map。
所以这样的事情将适用于原生 Promise.all,但不适用于我当前的实现
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); // it works
我修改了我的Promise.all,首先添加了一个检查以查看它是否具有Symbol.iterator,以确保它是可迭代的。
Promise.all = function(promiseArray) {
if (!promiseArray[Symbol.iterator]) {
throw new TypeError('The arguments should be an iterable!')
}
return new Promise((resolve, reject) => {
try {
但挑战在于如何遍历可迭代对象。当前的实现是通过const length = promiseArray.length 获取if 的长度并使用for 循环执行它,但是只有数组具有length 属性,其他可迭代对象或迭代器如Set 或Map.values() 将没有该属性可用。
如何调整我的实现以支持其他类型的可迭代对象,例如原生 Promise.all 所做的
【问题讨论】:
-
Symbol.iterator确定for( ... of ... )是否有效,所以我想说只是利用它。无需测试符号,只需尝试使用try { for( of ) {}} catch (err) { ... }运行您想要运行的代码。你可以记录你在 for 循环中处理了多少事情,不需要.length属性。但是,您确实需要返回一个纯数组,其顺序与您开始(未解决)每个承诺时的顺序相同(根据@derpirscher 的评论)。 -
你的方法有一个更大的问题:一旦解决,
Promise.all必须返回一个包含与输入承诺相同顺序的结果的迭代。使用您的方法,您只是在结果可用时推送结果。因此,顺序可能是完全随机的......
标签: javascript promise