JS面试手写:Promise的静态方法

170 阅读4分钟
  1. resolve方法: Promise.resolve的用法相当于new Promise,并且执行resolve操作。

比如:

// 类方法Promise.resolve

const promise = Promise.resolve({ name: "why" })
// 相当于
const promise2 = new Promise((resolve, reject) => {
  resolve({ name: "why" })
 })

手写实现resolve方法:

static resolve(value) { return new Promise((resolve) => resolve(value)) }
  1. reject方法类似于resolve方法,只是会将Promise对象的状态设置为reject状态。 Promise.reject的用法相当于new Promise,只是会调用reject。 Promise.reject传入的参数无论是什么形态,都会直接作为reject状态的参数传递到catch的。

比如:

const promise = Promise.reject("rejected message") 
// 相当于 
const promise2 = new Promsie((resolve, reject) => {
    reject("rejected message") 
})

手写实现reject方法:

static reject(reason) { return new Promise((resolve, reject) => reject(reason)) }
  1. all方法的作用是将多个Promise包裹在一起形成一个新的Promise。

新的Promise状态由包裹的所有Promise共同决定:当所有的Promise状态变成fulfilled状态时,新的Promise状态为fulfilled,并且会将所有Promise的返回值组成一个数组;当有一个Promise状态为reject时,新的Promise状态为reject,并且会将第一个reject的返回值作为参数;

比如:

// 创建多个Promise
const p1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve(11111)
  }, 1000);
})

const p2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject(22222)
  }, 2000);
})

const p3 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve(33333)
  }, 3000);
})

// 需求: 所有的Promise都变成fulfilled时, 再拿到结果
// 意外: 在拿到所有结果之前, 有一个promise变成了rejected, 那么整个promise是rejected

// "aaaa"相当于Promise.resolve("aaaa")
Promise.all([p2, p1, p3, "aaaa"]).then(res => {
  console.log(res)
}).catch(err => {
  console.log("err:", err) // err: 22222
})

手写all方法:

static all(promises) { 
// 问题关键: 什么时候要执行resolve, 什么时候要执行reject 
return new Promise((resolve, reject) => { 
    const values = [] 
    promises.forEach(promise => { 
        promise.then(res => { 
            values.push(res) 
            // 如果所有的Promise都正确执行了 
            if (values.length === promises.length) { 
                resolve(values) 
            } 
        }, err => { 
        // 否则只要有一个执行错误就reject 
            reject(err) 
        }) 
    }) 
 }) 
}
  1. allSettled方法:在所有的Promise都有结果(settled),无论是fulfilled,还是reject时,才会有最终的状态,并且这个Promise的结果一定是fulfilled的。

该方法解决了all方法的缺陷:当有其中一个Promise变成reject状态时,新Promise就会立即变成对应的reject状态。那么对于resolved的,以及依然处于pending状态的Promise,我们是获取不到对应的结果的。

比如:

// 创建多个Promise
const p1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve(11111)
  }, 1000);
})

const p2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject(22222)
  }, 2000);
})

const p3 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve(33333)
  }, 3000);
})

// allSettled
Promise.allSettled([p1, p2, p3]).then(res => {
  console.log("res:",res)
}).catch(err => {
  console.log("err:",err)
})

// 输出
// res: [{
//     status: 'fulfilled',
//     value: 11111
//   },
//   {
//     status: 'rejected',
//     reason: 22222
//   },
//   {
//     status: 'fulfilled',
//     value: 33333
//   }
// ]

手写allSettled方法:

  static allSettled(promises) {
    return new Promise((resolve) => {
      const results = []
      promises.forEach(promise => {
        promise.then(res => {
          results.push({ status: PROMISE_STATUS_FULFILLED, value: res})
          if (results.length === promises.length) {
            resolve(results)
          }
        }, err => {
          results.push({ status: PROMISE_STATUS_REJECTED, value: err})
          if (results.length === promises.length) {
            resolve(results)
          }
        })
      })
    })
  }
  1. race方法:如果有一个Promise有了结果,我们就希望决定最终新Promise的状态,那么可以使用race方法。多个Promise相互竞争,谁先有结果,那么就使用谁的结果。

比如:

// 创建多个Promise
const p1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve(11111)
  }, 3000);
})

const p2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject(22222)
  }, 500);
})

const p3 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve(33333)
  }, 1000);
})

// race: 竞技/竞赛
// 只要有一个Promise变成fulfilled/rejected状态, 那么就结束
Promise.race([p1, p2, p3]).then(res => {
  console.log("res:", res)
}).catch(err => {
  console.log("err:", err)
})

手写race方法:

  static race(promises) {
    return new Promise((resolve, reject) => {
      promises.forEach(promise => {
        // promise.then(res => {
        //   resolve(res)
        // }, err => {
        //   reject(err)
        // })
        promise.then(resolve, reject)
      })
    })
  } 
  1. any方法:any方法会等到一个fulfilled状态,才会决定新Promise的状态,如果所有的Promise都是reject的,那么也会等到所有的Promise都变成rejected状态,会报一个AggregateError的错误。

比如:

// 创建多个Promise
const p1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    // resolve(11111)
    reject(1111)
  }, 1000);
})

const p2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject(22222)
  }, 500);
})

const p3 = new Promise((resolve, reject) => {
  setTimeout(() => {
    // resolve(33333)
    reject(3333)
  }, 3000);
})

// any方法
Promise.any([p1, p2, p3]).then(res => {
  console.log("res:", res)
}).catch(err => {
  console.log("err:", err.errors) // err:[1111,22222,3333]
})

手写any方法:

  static any(promises) {
    // resolve必须等到有一个成功的结果
    // reject所有的都失败才执行reject
    const reasons = []
    return new Promise((resolve, reject) => {
      promises.forEach(promise => {
        promise.then(resolve, err => {
          reasons.push(err)
          if (reasons.length === promises.length) {
            reject(new AggregateError(reasons))
          }
        })
      })
    })
  }