手写Promise(二)——catch、finally和类方法

59 阅读4分钟

前言:昨日分享到then方法,今日继续分享剩余的方法。在理解此文章之前,务必把(一)消化哦!

一、catch:

catch(onRejected) {
   return this.then(undefined, onRejected)
  }
  
  ----------------以下为catch方法测试代码------------

p1.then(res => {
  console.log("res:", res)
}).catch(err => {
  console.log("err:", err)
})

这样写会出现问题:假如P1没有传err,则onRejected函数就为空了;正确的思路是假如没有传,则默认throw err===》基于此,设置onRejected的默认值来解决这个问题。 因此,修改then代码如下:

then(onFulfilled, onRejected) {
    const defaultOnRejected = (err => { throw err })
    onRejected = onRejected || defaultOnRejected
//--------------------以上是新增的代码-------------------------------
    return new selfPromise((resolve, reject) => {
//同之前代码相同
    }
  }

二、finally:

  finally(onFinally) {
   return this.then(() => {
      onFinally()
    }, () => {
      onFinally()
    })
  }
// ----------------以下为finally方法测试代码------------

p1.then(res => {
  console.log("res1:", res)
  return "aaaaa"
}).then(res => {
  console.log("res2:", res)
}).catch(err => {
  console.log("err:", err)
}).finally(() => {
  console.log("finally")
})

问题:调完then==>调catch===>调finally。注意:因为catch(undefined,onRejected),这个undefined隔绝了then的onFulfilled函数向finally的传递,出现了断层。 对策:设置onFulfilled的默认值。

then(onFulfilled, onRejected) {
    const defaultOnFulfilled = value => { return value }
    onFulfilled = onFulfilled || defaultOnFulfilled
    return new selfPromise((resolve, reject) => {
//同之前代码相同
     }
   }

四、类方法

4.1 resolve 和reject

static resolve(value) 方法中,只需要将 Promise 的状态设置为已完成(fulfilled)并传递对应的 value 值即可。因此,只需要调用 resolve(value) 即可。

而在 static reject(reason) 方法中,需要将 Promise 的状态设置为已拒绝(rejected)并传递拒绝的原因(reason),因此既需要resolve,也需要传reject。

  static resolve(value) {
    return new selfPromise((resolve) => {
      resolve(value)
    })
  }

  static reject(reason) {
    return new selfPromise((resolve, reject) => {
      reject(reason)
    })
  }

4.2 all : 可以理解为需要“全部”满足条件才会成功。

  static all(promises) {
    return new selfPromise((resolve, reject) => {
      const values = []
      promises.forEach((promise) => {
        promise.then(res => {
          values.push(res)
          if(values.length === promises.length) {
            resolve(values)
          }
        }, err => {
          reject(err)
        })
      })
    })

  }

4.3 any:可以理解为只需要“任意一个”满足条件就会成功(与all相反)

  static any(promises) {
    const reasons = []
    return new selfPromise((resolve, reject) => {
      promises.forEach(promise => {
        promise.then(res => {
          resolve(res)
        }, err => {
          reasons.push(err)
          if(reasons.length === promises.length) {
            reject(new AggregateError(reasons))
          }
        })
      })
    })
  }

补充:AggregateError是在 ECMAScript 2021 (ES12) 中引入的内置错误类型,较低版本的node不支持,可以通过errors属性在浏览器查看;AggregateError对象包含一个 errors 属性,该属性是一个数组,存储了多个错误对象。

4.4 allSettled:等待所有的 Promise 实例都被解决(settled),不论是成功还是失败。所以Promise.allSettled 的结果永远是已解决的(resolved)。

  static allSettled(promises) {
    return new selfPromise(resolve =>{
      const results = []
      promises.forEach((promise) => {
        promise.then(res => {
          results.push({status: FULFILLED, value: res})
          if(results.length === promises.length) {
            resolve(results)
          }
        }, err => {
          results.push({status: REJECTED, value: err})
          if(results.length === promises.length) {
            resolve(results)
          }
        })
      })
    })
  }

注意:返回结果是一个数组对象,每个结果对象包含以下两个属性:

  • status"fulfilled"(已完成)或 "rejected"(已拒绝)。
  • valuereason:表示对应 Promise 实例的值(如果状态为 "fulfilled")或拒绝原因(如果状态为 "rejected")。

4.5 race :类似于多个参与者之间的竞赛,谁先跑完,就先返回结果,不论成败。

 static race(promises) {
    return new selfPromise(((resolve, reject) => {
      promises.forEach(promise => {
        promise.then(resolve, reject)
      })
    }))
  }

五、手写全部promise代码及测试代码(可copy后自己在编辑器测试帮助自己理解)

const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'reject'



class selfPromise {
  constructor(executor) {
    this.status = PENDING
    this.value = undefined
    this.reason = undefined
    this.onFulfilledFns = []
    this.onRejectedFns = []

    const resolve = (value) => {
      if (this.status === PENDING) {
        queueMicrotask(() => {
          if (this.status !== PENDING) return
          this.value = value
          this.status = FULFILLED
          this.onFulfilledFns.forEach((fn) => {
            fn(this.value)
          })
        })
      }

    }

    const reject = (reason) => {
      if (this.status === PENDING) {
        queueMicrotask(() => {
          if (this.status !== PENDING) return
          this.reason = reason
          this.status = REJECTED
          this.onRejectedFns.forEach(fn => {
            fn(this.reason)
          })
        })
      }
    }

    try {
      executor(resolve, reject)
    } catch (error) {
      reject(error)
    }
  }

  then(onFulfilled, onRejected) {
    const defaultOnRejected = (err => { throw err })
    onRejected = onRejected || defaultOnRejected
    
    const defaultOnFulfilled = value => { return value }
    onFulfilled = onFulfilled || defaultOnFulfilled

    return new selfPromise((resolve, reject) => {
      if (this.status === PENDING) {
        if (onFulfilled) {
          this.onFulfilledFns.push(() => {
            try {
              const value = onFulfilled(this.value)
              resolve(value)
            } catch (error) {
              reject(error)
            }
           
          })
        }
        if (onRejected) {
          this.onRejectedFns.push(() => {
            try {
              const reason = onRejected(this.reason)
              resolve(reason)
            } catch (error) {
              reject(error)
            }

          })
        }
      }

      if (this.status === FULFILLED && onFulfilled) {
        // onFulfilled(this.value)
        try {
          const value = onFulfilled(this.value)
          resolve(value)
        } catch (error) {
          reject(error)
        }
      }

      if (this.status === REJECTED && onRejected) {
        // onRejected(this.reason)
        try {
          const reason = onRejected(this.reason)
          resolve(reason)
        } catch (error) {
          reject(error)
        }

      }
    })

  }

  catch(onRejected) {
   return this.then(undefined, onRejected)
  }

  finally(onFinally) {
   return this.then(() => {
      onFinally()
    }, () => {
      onFinally()
    })
  }

  static resolve(value) {
    return new selfPromise((resolve) => {
      resolve(value)
    })
  }

  static reject(reason) {
    return new selfPromise((resolve, reject) => {
      reject(reason)
    })
  }

  static all(promises) {
    return new selfPromise((resolve, reject) => {
      const values = []
      promises.forEach((promise) => {
        promise.then(res => {
          values.push(res)
          if(values.length === promises.length) {
            resolve(values)
          }
        }, err => {
          reject(err)
        })
      })
    })

  }

  static allSettled(promises) {
    return new selfPromise(resolve =>{
      const results = []
      promises.forEach((promise) => {
        promise.then(res => {
          results.push({status: FULFILLED, value: res})
          if(results.length === promises.length) {
            resolve(results)
          }
        }, err => {
          results.push({status: REJECTED, value: err})
          if(results.length === promises.length) {
            resolve(results)
          }
        })
      })
    })
  }

  static race(promises) {
    return new selfPromise(((resolve, reject) => {
      promises.forEach(promise => {
        promise.then(resolve, reject)
      })
    }))
  }

  static any(promises) {
    const reasons = []
    return new selfPromise((resolve, reject) => {
      promises.forEach(promise => {
        promise.then(res => {
          resolve(res)
        }, err => {
          reasons.push(err)
          if(reasons.length === promises.length) {
            reject(new AggregateError(reasons))
          }
        })
      })
    })
  }
}



//——————————————————测试代码————————————————————————————————

const p1 = new selfPromise((resolve, reject) => {
  // resolve(111111)
  reject(222222)
})
//-------以下为then方法的多次调用测试代码
// p1.then(res => {
//   console.log("res", res)
// }, err => {
//   console.log("err", err)
// })

// p1.then(res2 => {
//   console.log("res2", res2)
// }, err2 => {
//   console.log("err2", err2)
// })
// ----------以下为then方法的链式调用测试代码---------
// p1.then(res => {
//   console.log("res", res)
// }, err => {
//   console.log("err", err)
//   return "aaa"
// }).then(res2 => {
//   console.log("res2", res2)
// }, err2 => {
//   console.log("err2", err2)
// })

// ----------------以下为catch方法测试代码------------

// p1.then(res => {
//   console.log("res:", res)
// }).catch(err => {
//   console.log("err:", err)
// })
// ----------------以下为finally方法测试代码------------

// p1.then(res => {
//   console.log("res1:", res)
//   return "aaaaa"
// }).then(res => {
//   console.log("res2:", res)
// }).catch(err => {
//   console.log("err:", err)
// }).finally(() => {
//   console.log("finally")
// })
//-------------------以下是类方法:resolve、rejected的测试代码

// selfPromise.resolve("我是value").then(res => {
//   console.log("res", res)
// })

// selfPromise.reject("我是reason").catch(err => {
//   console.log("Error", err)
// })
//-------------------以下是类方法:all的测试代码
const promise1 = new Promise((resolve,reject) => {
  setTimeout(() => { reject(1111) }, 5000)
})
const promise2 = new Promise((resolve, reject) => {
  setTimeout(() => { reject(2222) }, 2000)
})
const promise3 = new Promise((resolve, reject) => {
  setTimeout(() => { reject(3333) }, 3000)
})

// selfPromise.all([promise1, promise2, promise3]).then(res => {
// console.log("all",res)
// }).catch(err => {
//   console.log("err", err)
// // })
// //-------------------以下是类方法:allSettled的测试代码
// selfPromise.allSettled([promise1, promise2, promise3]).then(res => {
// console.log("allSettled",res)
// }).catch(err => {
//   console.log("err", err)
// })

// //-------------------以下是类方法:race的测试代码
// selfPromise.race([promise1, promise2, promise3]).then(res => {
//   console.log("race",res)
//   }).catch(err => {
//     console.log("err", err)
//   })
  // //-------------------以下是类方法:any的测试代码
selfPromise.any([promise1, promise2, promise3]).then(res => {
  console.log("any",res)
  }).catch(err => {
    console.log("errs", err.errors)
  })