手撕Promise

2023-12-27 17:07:04

实现一个promise我个人分为几步

  1. 定义状态和值
  2. 初始化状态和值
  3. 实现resolve和reject方法来改变状态,这里需要注意报错处理和状态确定后就不可改变和this指向问题
  4. 定义任务队列保存下需要执行的函数,在状态改变时去执行
  5. 实现then 执行任务队列,需要判断传入参数不为function 为function和返回一个promise的情况

个人感觉promise源码难点在于状态的透传切换执行成功和失败的方法

      const state = {
        pending: 0, // 等待
        fulfilled: 1, // 成功
        rejected: 2, // 错误
      }
      // 创建一个"微任务"
      const runMicroTask = (fn) => {
        // 实际上setTimeout并不加入微任务队列,会加入延时队列(w3c已不再推荐使用宏任务微任务来描述)
        // 这里重点是promise所以暂且就使用setTimeout代替,也可以使用MutationObserver来真正的加入到微任务队列
        setTimeout(fn, 0)
      }
      // 如何判断是promise,按照promise A+ 规范来说 一个对象有then 并且是一个方法 那就是一个promise
      const isPromise = (obj) => {
        return !!(obj && typeof obj === "object" && typeof obj.then === "function")
      }
      class myPromise {
        constructor (executor) {
          // 初始化为等待状态
          this._state = state.pending
          this._value = null
          // 定义任务队列 在状态改变的时候循环执行里面保存的函数
          this.handleList = []
          try {
            // 创建promise会同步执行一次
            executor(this.resolve, this.reject)
          } catch (error) {
            // 执行出错的处理
            this.reject(error)
          }
        }
        // 抽离出一个修改状态的方法
        setState  = (state, value) => {
          if (state === state.pending) {
            return 
          }
          this._state = state
          this._value = value
          // 循环执行任务队列
          this.runHandleList()
        }
        // 成功
        resolve = (value) => {
          this.setState(state.fulfilled, value)
        }
        // 错误
        reject = (value) => {
          this.setState(state.rejected, value)
        }
        
        // then接收两个参数 一个为成功执行的函数一个为失败执行的函数
        then = (
          handleFulfilled,
          handleRejected
        ) => {
          // 之所以可以链式调用就是因为返回了myPromise类 里面有then方法 
          return new myPromise((resolve, reject) => {
            // 传入handleFulfilled 成功处理函数 handleRejected 错误处理函数 
            // 传入resolve reject来确定当前函数执行后的状态 成功就调用resolve失败执行reject
            this.pushHandleItem({handleFulfilled, handleRejected, resolve, reject})
            // 这里执行是应为 当前状态可能已经确定了 所以要检查一下
            this.runHandleList()
          })
        }

        // 把函数加入任务队列
        pushHandleItem = ({handleFulfilled, handleRejected, resolve, reject}) => {
          this.handleList.push({
            handle: handleFulfilled, state: state.fulfilled, resolve, reject
          })
          this.handleList.push({
            handle: handleRejected, state: state.rejected, resolve, reject
          })
        }

        runHandleList = () => {
          if (this._state === state.pending) {
            return
          }
          this.handleList.forEach(item => {
            // 放入微任务
            runMicroTask(this.runOneHandleItem(item))
          })
          // 执行完成后清空队列
          this.handleList = []
        }
        
        runOneHandleItem = ({handle, state: itemState, resolve, reject}) => {
          // 状态不匹配不做处理
          if (this._state !== itemState) return
          if (typeof handle !== 'function') { 
            // 状态透传
            itemState === state.fulfilled ? resolve(this._value) : reject(this._value)
            return
          }
          try {
            const val = handle(this._value)
            // 判断当前是否返回一个Promise如果是就调用自身的then方法把当前的状态交给返回的Promise处理
            if (isPromise(val)) {
              val.then(resolve, reject)
            } else {
              // 值透传
              resolve(val)
            }
          } catch (error) {
            // 失败时的处理
            reject(error)
          }
        }
        // catch直接调用then即可
        catch = (onRejected) => {
          return this.then(undefined, onRejected);
        };
      }

      const pro = new myPromise((resolve, reject) => {
        resolve('222222222')
      })
      pro.then(res => {
        console.log(res)
        return new myPromise((resolve, reject) => {
          reject('3333333333333333')
        })
      }).then(res => {
        console.log(res)
      }).catch(err => {
        console.log('err', err)
      })
      console.log(pro)

有不足和错误的地方望大佬指出我会及时修正

文章来源:https://blog.csdn.net/JasonAlonk/article/details/135248415
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。