bfe.dev 是一个针对前端的刷题网站,像是前端的LeetCode。该系列文章是我在上面的刷题日记。

题目32

BFE.dev#32 实现Promise.all()

分析

Promise.all()返回一个Promise,其

  1. 当所有的promise fulfill的时候fulfill
  2. 当任意一个promise reject的时候reject

显然我们可以给所有的promise添加新的handler,

  1. fulfill handler: 保存得到的数据,当检测到所有promise都已经resolve的时候resolve最终返回的promise
  2. 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...

希望能有所帮助,下次再见! 前端刷题!走起!


JSer
12 声望3 粉丝

[链接]