JS手写Promise 包含实例方法(catch,finally)和静态方法(resolve,reject,race,all,allSetted,any)

 // 异步执行 使用三种异步解决方案 queueMicrotask/MutationObserver/setTimeout  由于前面两种低版本浏览器不支持用setTimeout兜底
    function runAsynctask (callback) {
      // 如果当前浏览器支持queueMicortask 那么queueMicrotask==='function'成立 直接使用queueMicortask处理异步
      if (typeof queueMicrotask === 'function') {
        queueMicrotask(callback) //queueMicrotask是一个函数直接调用即可
        // MutationObserver MutationObserver==='function'成立 MutationObserver
      } else if (typeof MutationObserver === "function") {
        // MutationObserver的使用 首先需要new MutationObserver 创建一个实例 
        // 通过这个实例的observe方法传入两个参数 第一个参数是一个节点 第二个参数是一个对象 需要设置为childList:true
        // 当这个节点发生改变时触发这个MutationObserver 进而异步执行
        const obs = new MutationObserver(callback)
        const divNode = document.createElement("div")
        obs.observe(divNode, { childList: true })
        divNode.innerText = 'test'
      } else {
        // 最后使用setTimeout进行兜底 如果低版本的浏览器不支持前两种 直接使用setTimeout处理异步
        setTimeout(callback)
      }
    }

    // 封装重复引用报错
    function resolvePromise (x, p2, resolve, reject) {
      if (x === p2) {
        // 如果返回的对象和引用的对象相同则抛出错误
        throw new TypeError("Chaining cycle detected for promise #<Promise>")
      }
      // 如果返回的是一个Mypromise 则直接调用then方法
      if (x instanceof MyPromise) {
        x.then(res => resolve(res), err => reject(err))
      } else {
        resolve(x)
      }
    }

    // 定义三个状态
    const PENDING = "pending"
    const FULFILLED = "fulfilled"
    const REJECTED = "rejected"

    class MyPromise {
      state = PENDING //记录当前状态
      result = undefined //存储传入结果
      #handlers = [] // 存储多次调用

      constructor(func) {

        const resolve = (result) => {

          if (this.state === PENDING) {
            this.state = FULFILLED  // 如果当前状态是pending的话 执行resolve时把当前状态置为fulfilled
            this.result = result  //  用result来接受resolve传入的值
            this.#handlers.forEach(({ onFulfilled }) => {
              onFulfilled(this.result)
            }) //用来处理 多次调用的情况 就比如说在3s 之后才执行resolve 
            // 再次之前状态一直是pending,而且后面有好几个then,
            // 这时就通过handlers先把所有的方法都存储起来,当状态改为fulfilled时遍历执行所有的resolve()
          }
        }

        const reject = (result) => {
          if (this.state === PENDING) {
            this.state = REJECTED //如果当前状态是pending的话 执行reject时把当前状态置为rejected
            this.result = result
            this.#handlers.forEach(({ onRejected }) => {
              onRejected(this.result)
            })//用来处理 多次调用的情况 就比如说在3s 之后才执行reject
            // 再次之前状态一直是pending,而且后面有好几个then,
            // 这时就通过handlers先把所有的方法都存储起来,当状态改为fulfilled时遍历执行所有的reject()
          }
        }
        try {
          func(resolve, reject) //实例化Mypromise立即执行func()
        } catch (error) {
          reject(error) //如果报错 立即捕获错误并返回报错原因 
        }
      }


      //then 方法
      then (onFulfilled, onRejected) {
        // 根据MDN 仿写Promise 如果onFulfilled 不是一个函数 返回 x=>x
        // 如果onRejected不是函数 返回 x=>{throw x}
        onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : x => x
        onRejected = typeof onRejected === 'function' ? onRejected : x => { throw x }
        // then的返回值是Promise 这里new 一个MyPromise用p2来接受 方便后面返回
        const p2 = new MyPromise((resolve, reject) => {

          if (this.state === FULFILLED) {
            runAsynctask(() => {
              try {
                const x = onFulfilled(this.result)
                resolvePromise(x, p2, resolve, reject)
              } catch (error) {
                reject(error)
              }
            })
          }
          else if (this.state === REJECTED) {
            runAsynctask(() => {
              try {
                onRejected(this.result)
                resolvePromise(x, p2, resolve, reject)
              } catch (error) {
                reject(error)
              }

            })
          }
          else if (this.state === PENDING) {
            this.#handlers.push({
              onFulfilled: () => {
                runAsynctask(() => {
                  try {
                    const x = onFulfilled(this.result)
                    resolvePromise(x, p2, resolve, reject)
                  } catch (error) {
                    reject(error)
                  }
                })
              }
              , onRejected: () => {
                runAsynctask(() => {
                  try {
                    const x = onRejected(this.result)
                    resolvePromise(x, p2, resolve, reject)
                  } catch (error) {
                    reject(error)
                  }
                })
              }
            })
          }
        })
        return p2

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

      finally (onFulfilled) {
        return this.then(onFulfilled, onFulfilled)
      }

      static resolve (value) {
        //接受promise对象直接返回,如果不是promise 将其转为promise 并将传入的值作为resolve的参数
        if (value instanceof MyPromise) {
          return value
        } else {
          return new MyPromise((resolve, reject) => resolve(value))
        }
      }

      static reject (value) {

        return new MyPromise((resolve, reject) => reject(value))
      }
      static race (promises) {
        return new MyPromise((resolve, reject) => {
          if (!Array.isArray(promises)) {
            return reject(new TypeError('Argument is not iterable'))
          }

          promises.forEach(p => {
            MyPromise.resolve(p).then(res => resolve(res), err => reject(err))
          })
        })
      }

      static all (promises) {
        return MyPromise((resolve, reject) => {
          if (!Array.isArray(promises)) {
            return reject(new TypeError('Argument is not iterable'))
          }
          promises.length === 0 && resolve(promises) //&& 短路运算符 如果前面为true 则执行后面的逻辑

          const results = []
          const count = 0 //记录兑现次数,当兑现次数与传入数组的长度一致时,results就拿到的所有的结果
          promises.forEach((p, index) => {
            MyPromise.resolve(p).then(
              res => {
                results[index] = res//index是为了保证结果的顺序与Promise数组的顺序一致 
                count++
                count === promises.length && resolve(results)//如果全部兑现了就把results这个数组传递出去
              }, err => {
                reject(err)
              }
            )
          })
        })
      }
      static allSettled (promises) {
        return new MyPromise((resolve, reject) => {
          if (!Array.isArray(promises)) {
            return resolve(new TypeError("Argument is not iterable"))
          }

          promises.length === 0 && resolve(promises)
          let results = []
          let count = 0
          promises.forEach((p, index) => {
            MyPromise.resolve(p).then(res => {
              results[index] = { state: FULFILLED, value: res }
              conut++
              conut === promises.length && resolve(results)
            }, err => {
              results[index] = { state: REJECTED, value: err }
              conut++
              conut === promises.length && resolve(results)
            })
          })
        })
      }
      static any (promises) {
        return new MyPromise((resolve, reject) => {
          if (!Array.isArray(promises)) {
            return resolve(new TypeError('Argument is not iterable'))
          }

          promises.length === 0 && reject(new AggregateError(promises, "All promises were rejected"))
          let errors = []
          let count = 0
          promises.forEach((p, index) => {
            MyPromise.resolve(p).then(res => {
              resolve(res)
            }, err => {
              errors[index] = err
              count++
              count === promises.length && reject(new AggregateError(promises, "All promises were rejected"))
            })
          })

        })
      }
    }
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

、信仰_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值