Promise原理、以及Promise.race、Promise.all、Promise.resolve、Promise.reject实现;

为了向那道光亮奔过去,他敢往深渊里跳;

于是今天朝着Promise的实现前进吧,写了四个小时,终于完结撒花;

我知道大家没有耐心,当然我也坐的腰疼,直接上代码,跟着我的注释一行行看过去,保证门清

javascript 复制代码
const PENDING = "pending"
const FULFILLED = "fulfilled"
const REJECTED = "rejected"
// 提前封装好一个判断promise的 这里不用instanceof 因为有可能在我们的then的参数中,有可能是别人或者自己的promise
const isPromise = value => {
  return (
    !!value &&
    (typeof value === "object" || typeof value === "function") &&
    typeof value.then === "function"
  )
}
class MyPromise {
  #state = PENDING // 当前执行状态
  #result = undefined // 当前结果值
  #handler = [] // 记录成功与失败回调的数组
  constructor(executor) {
    const resolve = value => {
      // resolve之后去改变当前状态为成功 与当前成功的值
      this.#changeState(value, FULFILLED)
    }

    const reject = reason => {
      // reject之后去改变当前状态为失败 与当前错误的值
      this.#changeState(reason, REJECTED)
    }
    try {
      // 这里直接执行参数中的函数
      executor(resolve, reject)
    } catch (error) {
      console.error(error)
      // 这里try catch 错误就走reject
      reject(error)
    }
  }
  
 // 将传入的函数放到微队列中去执行
 #runMicroTask(runTask) {
   // 如果不兼容promise
    if (typeof Promise === "function") {
      return Promise.resolve().then(runTask)
    }
    // MutationObserver兼容性更好
    if (typeof MutationObserver === "function") {
      const ob = new MutationObserver(runTask)
      const node = document.createTextNode("")
      ob.observe(node, { characterData: true })
      node.data = 1
      return
    }
    // 如果是node环境
    if (process.nextTick && typeof process.nextTick === "function") {
      process.nextTick(runTask)
    }
  } 
  // 改变状态 保存此次的值 并且执行回调
  #changeState(result, state) {
    if (this.#state != PENDING) return
    this.#state = state
    this.#result = result
    this.#run()
  }
  // 这里跑每次then后的回调
  #runOne(callback, resolve, reject) {
    // 这里主要是为了模拟微任务 都是伪代码
    this.#runMicroTask(() => {
      // 如果为函数
      if (typeof callback === "function") {
        try {
          // 拿到函数的返回值
          const data = callback(this.#result)
          // 如果是promise包括别人封装的promise
          if (isPromise(data)) {
            console.log("data", data)
            // 如果是promise那就直接去执行.then 函数
            // 这里需要注意 这个resolve 是给下一个 所以这里这个resolve函数里带有上一次then返回来的值的!
            /* 可以看这里的注释来理解
      p.then(testMap.promiseTask, err => {
        console.log("第一次err err", err)
        throw "不好意思"
      })
        .then(
          res => {
            return new MyPromise(mySuc => {
              console.log("第二次", res)
                mySuc("MyPromise的值" + res)
            })
          },
          err => {
            console.log("第二次err err", err)
          }
        )
      */
            data.then(resolve, reject)
          } else {
            // 否则就自行resolve 把then(suc=>return '结果值') 就把这个data结果值给下一次调用的then传递过去
            resolve(data)
          }
        } catch (error) {
          // 不用解释了吧
          console.error(error)
          reject(error)
        }
      } else {
        // 如果不是函数 就直接执行resolve
        const settled = this.#state === FULFILLED ? resolve : reject
        settled(this.#result)
      }
    })
  }

  #run() {
    if (this.#state === PENDING) return
    /*
把下面的注释拿上来 主要为了能一次看懂不来回跳动
这里做push主要是
const p = new MyPromise之后
p.then(res=>fn1(res))
p.then(res=>fn2(res))
记录两次 fn1 与fn2
当然如果不是链式调用其实两次的拿到的回调值都是一样的
*/
    while (this.#handler.length) {
      // 这里需要注意的是resolve 与reject用的是实际then函数中传递的resolve与reject 不是当前类中的resolve
      const { onFulfilled, onRejected, resolve, reject } =
        this.#handler.shift()
      //  这里主要是为了简化代码 传递了此次
      this.#runOne(
        this.#state === FULFILLED ? onFulfilled : onRejected,
        resolve,
        reject
      )
    }
  }

  then(onFulfilled, onRejected) {
    return new MyPromise((resolve, reject) => {
      /*
这里做push主要是
const p = new MyPromise之后
p.then(res=>fn1(res))
p.then(res=>fn2(res))
记录两次 fn1 与fn2
当然如果不是链式调用其实两次的拿到的回调值都是一样的
*/
      this.#handler.push({
        onFulfilled,
        onRejected,
        resolve,
        reject,
      })
      this.#run()
    })
  }
  //catch方法的封装 catch 的话直接让它执行错误代码就好了 
  // 可不要以为有这样的代码比如Promise.catch 没有哈 都是new Promise的回调函数reject执行后的,所以这里只要让它有这个 reject方法就行了!
  catch(onRejected) {
    return this.then(undefined, onRejected)
  }

  //resolve方法的封装,凡是被static修饰的属性和方法都是静态方法和属性,只能被类名调用
  //不能被实例化对象调用.同时也不能被子类继承,换句话说它属于当前这个类的.
  static resolve(value) {
    //返回结果为Promise对象
    // 这里呢需要判断他是不是promise resolve中可能是个promise 
    return new MyPromise((resolve, reject) => {
      if (isPromise(value)) {
        value.then(
          v => {
            resolve(v)
          },
          r => {
            reject(r)
          }
        )
      } else {
        resolve(value)
      }
    })
  }

  //reject方法的封装 reject都是出错这种明确值,所以这里不需要判断 你给啥,我给下一个error给啥
  static reject(value) {
    return new MyPromise((resolve, reject) => {
      reject(value)
    })
  }
  //all方法的封装
  static all(promises) {
    const self = this
    return new MyPromise((resolve, reject) => {
      let length = promises.length // 缓存一下有多少个promise
      let count = 0 // 用于记录resolve的数量
      let values = new Array(length) // 用于存储resolve返回的值
      for (let i = 0; i < length; i++) {
        let promise = promises[i]
        // 判断数组的每一项,如果是promise,就进入then,不是就直接放进values数组中返回
        if (isPromise(promise)) {
          promise
            .then(res => {
              // 记录promise完成的数量
              count++
              // values存储每一个promise的res
              values[i] = res
              // 由于异步代码在最后执行,我们需要在then里面判断promise的完成数量,全部完成就resolve
              // 在for外面判断,是防止它全部都不是promise实例
              if (count === length) {
                resolve(values)
              }
            })
            .catch(err => {
              // 当有一个promise实例reject,我们就直接reject
              reject(err)
            })
        } else {
          // 针对不是promise实例
          count++
          values[i] = promise
        }
      }
      // 当数据的所有项都不是promise实例,我们就在这判断多一次,然后resolve
      if (count === length) {
        resolve(values)
      }
    })
  }
  //race方法的封装
  static race(promises) {
    return new MyPromise((resolve, reject) => {
      const len = promises.length
      for (let i = 0; i < len; i += 1) {
        const promise = promises[i]
        // 只要有一条成功则全部成功
        promise.then(
          res => {
            resolve(res)
          },
          error => {
            resolve(error)
          }
        )
      }
    })
  }
}
window.MyPromise = MyPromise

const test1 = new MyPromise(suc => {
  setTimeout(() => suc("成功 p"), 1001)
})
const test2 = new MyPromise((resolve, reject) => {
  setTimeout(() => {
    reject(3)
  }, 1000)
})
const test3 = new MyPromise(suc => {
  setTimeout(() => suc("成功 test3"), 1019)
})
MyPromise.all([test2, test1, test3])
  .then(res => {
    console.log("res all", res)
  })
  .catch(res => {
    console.log("error", res)
  })
MyPromise.race([test2, test1, test3])
  .then(res => {
    console.log("res race", res)
  })
  .catch(res => {
    console.log("error", res)
  })

const catchTest = new MyPromise((resolve, reject) => {
  setTimeout(() => {
    reject("catch 测试")
  }, 1000)
}).catch(error => {
  console.error(error)
})

const p = new MyPromise((resolve, reject) => {
  setTimeout(() => {
    resolve(3)
  }, 1000)
})

const testMap = {
  promiseTask: res => {
    console.log("第一次 ===>", res)
    return new Promise(suc => {
      suc("promise方式的res", res)
    })
  },
  funcTask: res => {
    console.log("第一次 ===>", res)
    return res
  },
  // 直接穿透第一次resolve 或者reject 值到下一条then函数中
  otherTask: "其他",
}

p.then(testMap.promiseTask, err => {
  console.log("第一次err err", err)
  throw "不好意思"
})
  .then(
    res => {
      return new MyPromise(mySuc => {
        console.log("第二次", res)
        mySuc("MyPromise的值" + res)
      })
    },
    err => {
      console.log("第二次err err", err)
    }
  )
  .then(
    res => {
      console.log("第三次", res)
      return "第三次的值" + res
    },
    err => {
      console.log("第三次err err", err)
    }
  )
  .then(
    res => {
      console.log("第四次", res)
    },
    err => {
      console.log("第四次err err", err)
    }
  )
相关推荐
2301_801074152 分钟前
TypeScript异常处理
前端·javascript·typescript
ᅠᅠᅠ@2 分钟前
异常枚举;
开发语言·javascript·ecmascript
caperxi4 分钟前
前端开发中的防抖与节流
前端·javascript·html
学习路上的小刘7 分钟前
vue h5 蓝牙连接 webBluetooth API
前端·javascript·vue.js
&白帝&7 分钟前
vue3常用的组件间通信
前端·javascript·vue.js
罗_三金28 分钟前
前端框架对比和选择?
javascript·前端框架·vue·react·angular
Fan_web1 小时前
JavaScript高级——闭包应用-自定义js模块
开发语言·前端·javascript·css·html
叫我:松哥1 小时前
基于Python flask的医院管理学院,医生能够增加/删除/修改/删除病人的数据信息,有可视化分析
javascript·后端·python·mysql·信息可视化·flask·bootstrap
好名字08212 小时前
monorepo基础搭建教程(从0到1 pnpm+monorepo+vue)
前端·javascript
c#上位机2 小时前
C#事件的用法
java·javascript·c#