bfe.dev 是一个针对前端的刷题网站,像是前端的LeetCode。该系列文章是我在上面的刷题日记。
题目32
BFE.dev#32 实现Promise.all()
分析
Promise.all()
返回一个Promise,其
- 当所有的promise fulfill的时候fulfill
- 当任意一个promise reject的时候reject
显然我们可以给所有的promise添加新的handler,
- fulfill handler: 保存得到的数据,当检测到所有promise都已经resolve的时候resolve最终返回的promise
- rejected handler: 立马reject最终返回的promise
开始写代码吧
首先,骨架代码如下,很容易理解
function all(promises) {
return new Promise((resolve, reject) => {
promises.forEach((promise, index) => {
promise.then((value) => {
// TODO
}, (error) => {
// TODO
})
})
})
}
fulfill的data需要存在一个数组里,但是promise的fulfill时机未知,先后顺序不定,所以不能push,而是利用index来放置数据到正确的位置。
这样做过后,存放数据的数组就不能通过length来判断是否所有的proimse都已经fulfill了,所以用另外一个变量来计数。
function all(promises) {
return new Promise((resolve, reject) => {
const result = []
let fulfilledCount = 0
promises.forEach((promise, index) => {
promise.then((value) => {
result[index] = value
fulfilledCount += 1
if (fulfilledCount === promises.length) {
resolve(result)
}
}, (error) => {
// TODO
})
})
})
}
处理rejection的时候比较简单,直接reject最后返回的promise即可。但是要注意reject过后,依然可能有promise继续fulfill或者reject,我们需要忽略这些情况,所以用一个isErrored
的flag即可。
function all(promises) {
return new Promise((resolve, reject) => {
const result = []
let fulfilledCount = 0
let isErrored = false
_promises.forEach((promise, index) => {
promise.then((value) => {
if (isErrored) return
result[index] = value
fulfilledCount += 1
if (fulfilledCount === _promises.length) {
resolve(result)
}
}, (error) => {
if (isErrored) return
isErrored = true
reject(error)
})
})
})
}
最后一部分就是关于输入处理的,因为Promise.all支持传入非Promise数据,所以在代码的一开始,我们将非Promise数据包装一下即可。最终得到如下代码!
function all(promises) {
const _promises = promises.map(
(item) => item instanceof Promise ? item : Promise.resolve(item)
)
// resolve if empty
if (_promises.length === 0) {
return Promise.resolve([])
}
return new Promise((resolve, reject) => {
const result = []
let fulfilledCount = 0
let isErrored = false
_promises.forEach((promise, index) => {
promise.then((value) => {
if (isErrored) return
result[index] = value
fulfilledCount += 1
if (fulfilledCount === _promises.length) {
resolve(result)
}
}, (error) => {
if (isErrored) return
isErrored = true
reject(error)
})
})
})
}
通过撒花!🎉
如果你感兴趣,可以在 BFE.dev 上试试 https://bigfrontend.dev/zh/pr...
希望能有所帮助,下次再见! 前端刷题!走起!
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。