手撕代码之--------Promise

53 阅读4分钟

不多BB直接展示

    <script>
      const PENDING = 'pending'
      const FULFILLED = 'fulfilled'
      const REJECTED = 'rejected'
      class MyPromise {
        state = PENDING
        result = undefined
        #handlers = []
        constructor(func) {
          const resolve = (res) => {
            if (this.state === PENDING) {
              this.state = FULFILLED
              this.result = res
              this.#handlers.forEach((item) => {
                item[0](res)
              })
            }
          }
          const reject = (err) => {
            if (this.state === PENDING) {
              this.state = REJECTED
              this.result = err
              this.#handlers.forEach((item) => {
                item[1](err)
              })
            }
          }
          try {
            func(resolve, reject)
          } catch (err) {
            reject(err)
          }
        }
        then(onFulfilled, onRejected) {
          // typeof
          onFulfilled =
            Object.prototype.toString.call(onFulfilled) === '[object Function]'
              ? onFulfilled
              : (x) => x
          onRejected =
            typeof onRejected === 'function'
              ? onRejected
              : (x) => {
                  throw x
                }
          const p2 = new MyPromise((rel, rej) => {
            if (this.state === FULFILLED) {
              runAsyncTask(() => {
                try {
                  const x = onFulfilled(this.result)
                  resolvePromise(p2, x, rel, rej)
                } catch (err) {
                  rej(err)
                }
              })
            } else if (this.state === REJECTED) {
              runAsyncTask(() => {
                try {
                  const x = onRejected(this.result)
                  resolvePromise(p2, x, rel, rej)
                } catch (err) {
                  rej(err)
                }
              })
            } else if (this.state === PENDING) {
              this.#handlers.push([
                () => {
                  runAsyncTask(() => {
                    try {
                      const x = onFulfilled(this.result)
                      resolvePromise(p2, x, rel, rej)
                    } catch (err) {
                      rej(err)
                    }
                  })
                },
                () => {
                  runAsyncTask(() => {
                    try {
                      const x = onRejected(this.result)
                      resolvePromise(p2, x, rel, rej)
                    } catch (err) {
                      rej(err)
                    }
                  })
                }
              ])
            }
          })

          return p2
        }
        catch(onRejected) {
          return this.then(undefined, onRejected)
        }
        finally(onFinally) {
          return this.then(onFinally, onFinally)
        }
        static resolve(val) {
          if (val instanceof MyPromise) {
            return val
          }
          return new MyPromise((res, rej) => {
            res(val)
          })
        }
        static reject(v) {
          return new MyPromise((undefined, rej) => {
            rej(v)
          })
        }
        static race(promiseArr) {
          return new MyPromise((reso, reje) => {
            // 判断是不是数组(可迭代对象)
            if (!promiseArr || !promiseArr[Symbol.iterator]) {
              reje(new TypeError('Argument is not iterable'))
            }
            promiseArr.forEach((el) => {
              MyPromise.resolve(el).then(
                (res) => {
                  reso(res)
                },
                (err) => {
                  reje(err)
                }
              )
            })
          })
        }
        static all(promiseArr) {
          return new MyPromise((reso, reje) => {
            // if (!Array.isArray(promiseArr)) {
            //   reje(new TypeError('Argument is not iterable'))
            // }
            // 判断是不是数组(可迭代对象)
            if (
              !promiseArr ||
              !(typeof promiseArr[Symbol.iterator] === 'function')
            ) {
              reje(new TypeError('Argument is not iterable'))
            }

            // console.log('123'[Symbol.iterator])
            // if (!promiseArr || !promiseArr[Symbol.iterator]) {
            // }
            promiseArr = Array.from(promiseArr)
            // if (promiseArr.length === 0) {
            //   reso(promiseArr)
            // }
            promiseArr.length === 0 && reso(promiseArr)
            const resArr = []
            let count = 0
            promiseArr.forEach((v, i) => {
              MyPromise.resolve(v).then(
                (res) => {
                  resArr[i] = res
                  count++
                  count === promiseArr.length && reso(resArr)
                },
                (err) => {
                  reje(err)
                }
              )
            })
          })
        }
        static allSettled(promiseArr) {
          return new MyPromise((reso, reje) => {
            // 判断是不是数组(可迭代对象)
            if (promiseArr[Symbol.iterator] === undefined) {
              reje(new TypeError('Argument is not iterable'))
            }
            promiseArr = Array.from(promiseArr)
            // if (promiseArr.length === 0) {
            //   reso(promiseArr)
            // }
            promiseArr.length === 0 && reso(promiseArr)
            const resArr = []
            let count = 0
            promiseArr.forEach((v, i) => {
              MyPromise.resolve(v).then(
                (res) => {
                  resArr[i] = { status: FULFILLED, value: res }
                  count++
                  count === promiseArr.length && reso(resArr)
                },
                (err) => {
                  resArr[i] = { status: REJECTED, reason: err }
                  count++
                  count === promiseArr.length && reso(resArr)
                }
              )
            })
          })
        }
        static any(promiseArr) {
          return new MyPromise((reso, reje) => {
            // 判断是不是数组(可迭代对象)
            if (promiseArr[Symbol.iterator] === undefined) {
              console.log(222)
              reje(new TypeError('Argument is not iterable'))
            }
            promiseArr = Array.from(promiseArr)
            // if (promiseArr.length === 0) {
            //   reso(promiseArr)
            // }
            promiseArr.length === 0 &&
              reje(new AggregateError(promiseArr, '123456789'))
            const errArr = []
            let count = 0
            promiseArr.forEach((v, i) => {
              MyPromise.resolve(v).then(
                (res) => {
                  reso(res)
                },
                (err) => {
                  errArr[i] = err
                  count++
                  count === promiseArr.length &&
                    reje(
                      new AggregateError(errArr, 'ALL Promise were rejected')
                    )
                }
              )
            })
          })
        }
      }
      // 抽取函数
      function resolvePromise(p2, x, rel, rej) {
        if (x === p2) {
          throw new TypeError(
            '123Chaining cycle detected for promise #<Promise>'
          )
        }
        if (x instanceof MyPromise) {
          x.then(
            (res) => {
              rel(res)
            },
            (err) => {
              rej(err)
            }
          )
        } else {
          rel(x)
        }
      }

      // 封装一个异步执行函数
      // 01. 自定义函数方式(命名函数)可以先调用在定义(变量提升)
      // 02. 函数表达式方式(匿名函数)不行
      const runAsyncTask = (callback) => {
        if (typeof queueMicrotask === 'function') {
          queueMicrotask(callback)
        } else if (typeof MutationObserver === 'function') {
          const obs = new MutationObserver(callback)
          const divNode = document.createElement('div')
          obs.observe(divNode, { childList: true })
          divNode.innerHTML = 'hello world'
        } else {
          setTimeout(callback, 0)
        }
      }
      const pp01 = new MyPromise((resolve, reject) => {
        setTimeout(() => {
          resolve(1111111)
        }, 1000)
      })
      pp01
        .then(
          (res) => {
            console.log(res)
            return 22222222
          },
          (rej) => {
            console.log(rej)
          }
        )
        .then(
          (res) => {
            console.log(res)
            return 33333333
          },
          (rej) => {
            console.log(rej)
          }
        )
      // ----------------------------测试MyPromise.any------------------
      // const p00001 = new MyPromise((res, rej) => {
      //   setTimeout(() => {
      //     rej(1)
      //   }, 1000)
      // })
      // const p00002 = MyPromise.reject({ na: 123 })
      // const p00003 = new MyPromise((res, rej) => {
      //   setTimeout(() => {
      //     // res(3)
      //     rej(3)
      //   }, 1000)
      // })
      // MyPromise.any([p00001, p00002, p00003]).then(
      //   (res) => {
      //     console.log('res', res)
      //   },
      //   (err) => {
      //     console.dir(err)
      //   }
      // )
      // ----------------------------测试MyPromise.allSettled------------------
      // const p00001 = MyPromise.resolve(1)
      // const p00002 = { na: 123 }
      // const p00003 = new MyPromise((res, rej) => {
      //   setTimeout(() => {
      //     rej(3)
      //   }, 1000)
      // })
      // MyPromise.allSettled(new Set([p00001, p00002, p00003])).then(
      //   (res) => {
      //     console.log('res', res)
      //   },
      //   (err) => {
      //     console.log('err', err)
      //   }
      // )
      // ----------------------------测试MyPromise.all------------------
      // Promise.all({})
      // const p001 = new MyPromise((res, rej) => {
      //   setTimeout(() => {
      //     res(1)
      //   }, 2000)
      // })
      // const p002 = new MyPromise((res, rej) => {
      //   setTimeout(() => {
      //     // rej(222222222)
      //     res(111111111)
      //   }, 1000)
      // })
      // MyPromise.race([]).then(
      //   (res) => {
      //     console.log('res', res)
      //   },
      //   (err) => {
      //     console.log(err)
      //   }
      // )
      // 申明复杂数据类型的的变量指的是该地址 申明基本数据类型的变量指的是值本身
      // const arr = [1, 2]
      // const arr01 = arr
      // arr01[1] = 3
      // console.log(arr)
      // console.log('arr01', arr01)

      // let s1 = '123'
      // let s2 = s1
      // console.log('s2', s2)
      // s2 = 3
      // console.log('s1', s1)
      // console.log('s2', s2)

      // ----------------------------测试MyPromise.race------------------
      // const p001 = new MyPromise((res, rej) => {
      //   setTimeout(() => {
      //     res(1)
      //   }, 2000)
      // })
      // const p002 = new MyPromise((res, rej) => {
      //   setTimeout(() => {
      //     rej(2)
      //   }, 1000)
      // })
      // MyPromise.race(new Set([p001, p002, 'ceshi'])).then(
      //   (res) => {
      //     console.log('res', res)
      //   },
      //   (err) => {
      //     console.log('err', err)
      //   }
      // )
      // ----------------------------测试MyPromise.resolve------------------
      // MyPromise.resolve(
      //   new MyPromise((res, rej) => {
      //     setTimeout(() => {
      //       res(1111111111)
      //     }, 2000)
      //   }).then(
      //     (res) => {
      //       console.log('res', res)
      //     },
      //     (err) => {
      //       console.log('err', err)
      //     }
      //   )
      // )
      // MyPromise.resolve('123').then(
      //   (res) => {
      //     console.log('res', res)
      //   },
      //   (err) => {
      //     console.log('err', err)
      //   }
      // )

      // --------------------------------------------------------------

      // MyPromise.resolve(
      //   new MyPromise((res, rej) => {
      //     res('res')
      //     // rej('rej')
      //     // throw 'error'
      //   })
      // ).then(
      //   (res) => {
      //     console.log('res', res)
      //   },
      //   (rej) => {
      //     console.log('rej', rej)
      //   }
      // )
      // MyPromise.resolve('测试').then((res) => {
      //   console.log(res)
      // })
      // MyPromise.reject('测试error').catch((res) => {
      //   console.log(res)
      // })
      // ---------------------------------------------------
      // console.log(new Error('我出错了01')) //Error: 我出错了01
      // console.log(new Err('我出错了02')) //Uncaught ReferenceError: Err is not defined

      // const p = new MyPromise((rel, rej) => {
      //   // setTimeout(() => {
      //   //   rel('success0000000000')
      //   //   // rej('err123456')
      //   // }, 1000)
      //   // rel('成功')
      //   // rej('failed')
      //   throw 'throw-error'
      // })
      // -------------------------辅助理解传入的回调函数----------------------
      // const rel = () => {
      //   console.log('成功')
      // }
      // const rej = () => {
      //   console.log('失败')
      // }
      // const xxx = (rel, rej) => {
      //   // 省略逻辑
      //   rel()
      //   rej()
      // }
      // xxx(rel, rej)

      // ----------------------------测试---------------------------------

      // const p3 = p
      //   .then(
      //     (res) => {
      //       // throw 'erro'
      //       // return p3
      //       // return 2
      //       console.log(res)
      //       // return new MyPromise((resolve, reject) => {
      //       //   resolve('Mp-3')
      //       //   // reject('Mp-error')
      //       // })
      //     }
      //     // (err) => {
      //     //   console.log('err1111', err)
      //     //   // throw 'erro'
      //     //   // return p3
## //     //   // return 2
      //     //   // return new MyPromise((resolve, reject) => {
      //     //   //   // resolve('Mp-3')
      //     //   //   reject('Mp-error')
      //     //   // })
      //     // }
      //   )
      //   .catch((err) => {
      //     console.log('catch', err)
      //   })
      //   .finally(() => {
      //     console.log('finally')
      //   })
      // p3.then(
      //   (res) => {
      //     console.log('p3-res', res)
      //   },
      //   (err) => {
      //     console.log('p3-err', err)
      //   }
      // )
      // .then(
      //   (res) => {
      //     console.log('success02', res)
      //     return 200
      //   },
      //   (err) => {
      //     console.log('failed02', err)
      //   }
      // )
      // console.log(111)
      // console.log(p)
      // ----------------------------异步核心api函数-----------------------------
      // queueMicrotask(() => {
      //   console.log(222)
      // })
      // const obs = new MutationObserver(() => {
      //   console.log(333)
      // })
      // const divNode = document.createElement('div')
      // obs.observe(divNode, { childList: true })
      // divNode.innerHTML = 'hello world'

      // ----------------------原生Promise-----------------------------
      // const pro = new Promise((s, r) => {
      //   s(0)
      // })
      // const pro01 = pro.then((res) => {
      //   return pro01
      // })
      // pro01.then((res) => {})
    </script>