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


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

    于是今天朝着Promise的实现前进吧,写了四个小时,终于完结撒花;
    我知道大家没有耐心,当然我也坐的腰疼,直接上代码,跟着我的注释一行行看过去,保证门清

    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)
        }
      )
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    • 275
    • 276
    • 277
    • 278
    • 279
    • 280
    • 281
    • 282
    • 283
    • 284
    • 285
    • 286
    • 287
    • 288
    • 289
    • 290
    • 291
    • 292
    • 293
    • 294
    • 295
    • 296
    • 297
    • 298
    • 299
    • 300
    • 301
    • 302
    • 303
    • 304
    • 305
    • 306
    • 307
    • 308
    • 309
    • 310
    • 311
    • 312
    • 313
    • 314
    • 315
    • 316
    • 317
    • 318
    • 319
    • 320
    • 321
    • 322
    • 323
    • 324
    • 325
    • 326
    • 327
    • 328
    • 329
    • 330
    • 331
    • 332
    • 333
  • 相关阅读:
    视频流采集存储和展示技术调研
    Python 批量修改文件名
    IntelliJ IDEA Services工具栏运行不显示端口问题解决
    【Linux集群教程】01 集群概述 & 负载均衡集群
    37、api网关-kong
    【android】用 ExpandableListView 来实现 TreeView树形菜单视图
    【云原生kubernetes系列】--RBAC权限的使用
    MQTT X Newsletter 2022-07 | 自动更新、MQTT X CLI 支持 MQTT 5.0、新增 conn 命令…
    下列对“一带一路”倡议的认识中,正确的有()。 A 顺应时代潮流 B 适应发展规律 C 符合各国人民利益 D 具有广阔前景
    VMware虚拟机安装CentOS6.9设置静态ip
  • 原文地址:https://blog.csdn.net/xuewenjie0217/article/details/134367151