最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 一步步实现一个Promise

    正文概述 掘金(努力了吗梁同学)   2021-04-20   604

    1、前言

    本篇文章,默认你已经知道什么是 Promise ,然后我会带你一步步的实现一个简易的 Promise。将会以循序渐进的方式,分步骤实现。

    本文章相关代码地址:github.com/layouwen/bl…

    如果本文章对你有所帮助,请不要吝啬你的 Start 哦~

    2、三种状态

    此处代码,点击这里

    Promise 它一共会有三种状态:

    1. pending
    2. fulfilled
    3. rejected

    下面我们自己实现一个类,默认为 pending 状态,通过调用 resolve 或者 reject 改变其状态

    class LPromise {
      constructor(callbackFn) {
        this['[[PromiseState]]'] = 'pending'
        this['[[PromiseResult]]'] = undefined
        callbackFn(this.#resolve.bind(this), this.#reject.bind(this))
      }
      #resolve(res) {
        this['[[PromiseState]]'] = 'fulfilled'
        this['[[PromiseResult]]'] = res
      }
      #reject(err) {
        this['[[PromiseState]]'] = 'reject'
        this['[[PromiseResult]]'] = err
      }
    }
    console.log(new LPromise((resolve, reject) => console.log('pending'))) // pending 状态
    const l1 = new LPromise((resolve, reject) => {
      resolve('我调用了resolve')
    })
    console.log(l1) // fulfilled 状态
    const l2 = new LPromise((resolve, reject) => {
      reject('我调用了reject')
    })
    console.log(l2) // rejected 状态
    

    3、实现 then 参数回调

    此处代码,点击这里

    返回的 Promise ,可以通过使用 then 传递成功和失败的回调。

    通过 then 接收了两个回调。实现了分别调用回调的内容。但是发现,他们两个都会执行。

    class LPromise {
      constructor(callbackFn) {
        this['[[PromiseState]]'] = 'pending'
        this['[[PromiseResult]]'] = undefined
        callbackFn(this.#resolve.bind(this), this.#reject.bind(this))
      }
      #resolve(res) {
        this['[[PromiseState]]'] = 'fulfilled'
        this['[[PromiseResult]]'] = res
      }
      #reject(err) {
        this['[[PromiseState]]'] = 'reject'
        this['[[PromiseResult]]'] = err
      }
      /* new content start */
      then(onResolve, onReject) {
        onResolve()
        onReject()
      }
      /* new content end */
    }
    const l1 = new LPromise((resolve, reject) => resolve())
    l1.then(
      res => console.log('res'),
      err => console.log('err')
    )
    

    对执行时机进行调整。使其在调用 resolve 或 reject 才执行相关的回调

    class LPromise {
      constructor(callbackFn) {
        this['[[PromiseState]]'] = 'pending'
        this['[[PromiseResult]]'] = undefined
        callbackFn(this.#resolve.bind(this), this.#reject.bind(this))
      }
      #resolve(res) {
        this['[[PromiseState]]'] = 'fulfilled'
        this['[[PromiseResult]]'] = res
        /* new content start */
        this.cbResolve() // 报错
        /* new content end */
      }
      #reject(err) {
        this['[[PromiseState]]'] = 'reject'
        this['[[PromiseResult]]'] = err
        /* new content start */
        this.cbReject() // 报错
        /* new content end */
      }
      then(onResolve, onReject) {
        /* new content start */
        this.cbResolve = onResolve
        this.cbReject = onReject
        /* new content end */
      }
    }
    const l1 = new LPromise((resolve, reject) => resolve())
    l1.then(
      res => console.log('res'),
      err => console.log('err')
    )
    

    改装后,发现 resolve 和 reject 的执行时间比 then 的回调要快。导致无法执行 then 中的回调。我们需要对 resolve 和 reject 中执行回调的部分进行 延迟执行。可以使用 setTimeout 进行延迟

    class LPromise {
      constructor(callbackFn) {
        this['[[PromiseState]]'] = 'pending'
        this['[[PromiseResult]]'] = undefined
        callbackFn(this.#resolve.bind(this), this.#reject.bind(this))
      }
      #resolve(res) {
        this['[[PromiseState]]'] = 'fulfilled'
        this['[[PromiseResult]]'] = res
        /* new content start */
        setTimeout(() => this.cbResolve())
        /* new content end */
      }
      #reject(err) {
        this['[[PromiseState]]'] = 'reject'
        this['[[PromiseResult]]'] = err
        /* new content start */
        setTimeout(() => this.cbReject())
        /* new content end */
      }
      then(onResolve, onReject) {
        this.cbResolve = onResolve
        this.cbReject = onReject
      }
    }
    const l1 = new LPromise((resolve, reject) => resolve())
    l1.then(
      res => console.log('res'),
      err => console.log('err')
    )
    

    考虑到 微任务 和 宏任务。我们可以使用 MutationObserver 替代 setTimeout

    class LPromise {
      constructor(callbackFn) {
        this['[[PromiseState]]'] = 'pending'
        this['[[PromiseResult]]'] = undefined
        callbackFn(this.#resolve.bind(this), this.#reject.bind(this))
      }
      #resolve(res) {
        this['[[PromiseState]]'] = 'fulfilled'
        this['[[PromiseResult]]'] = res
        /* new content start */
        const run = () => this.cbResolve()
        const ob = new MutationObserver(run)
        ob.observe(document.body, { attributes: true })
        document.body.setAttribute('lpromise', 'layouwen')
        /* new content end */
      }
      #reject(err) {
        this['[[PromiseState]]'] = 'reject'
        this['[[PromiseResult]]'] = err
        /* new content start */
        const run = () => this.cbReject()
        const ob = new MutationObserver(run)
        ob.observe(document.body, { attributes: true })
        document.body.setAttribute('lpromise', 'layouwen')
        /* new content end */
      }
      then(onResolve, onReject) {
        this.cbResolve = onResolve
        this.cbReject = onReject
      }
    }
    const l1 = new LPromise((resolve, reject) => resolve())
    l1.then(
      res => console.log('res'),
      err => console.log('err')
    )
    

    4、链式调用

    此处代码,点击这里

    在原本的 Promise 中。我们是可以使用 then 链式调用。意味着每个 then 都返回一个新的 Promise

    因为支持链式。所以我们之前的 cbResolvecbReject 就不能单单保存一个回调。要改回一个数组,将每一个 then 中的回调。都保存到回调队列中。等待调用 resolve 或者 reject 后才执行所有回调函数。

    class LPromise {
      constructor(callbackFn) {
        this['[[PromiseState]]'] = 'pending'
        this['[[PromiseResult]]'] = undefined
        /* new content start */
        this.cbResolveQueue = []
        this.cbRejectQueue = []
        /* new content end */
        callbackFn(this.#resolve.bind(this), this.#reject.bind(this))
      }
      #resolve(res) {
        this['[[PromiseState]]'] = 'fulfilled'
        this['[[PromiseResult]]'] = res
        /* new content start */
        const run = () => {
          let cbFn
          while ((cbFn = this.cbResolveQueue.shift())) {
            cbFn && cbFn()
          }
        }
        /* new content end */
        const ob = new MutationObserver(run)
        ob.observe(document.body, { attributes: true })
        document.body.setAttribute('lpromise', 'layouwen')
      }
      #reject(err) {
        this['[[PromiseState]]'] = 'reject'
        this['[[PromiseResult]]'] = err
        /* new content start */
        const run = () => {
          let cbFn
          while ((cbFn = this.cbRejectQueue.shift())) {
            cbFn && cbFn()
          }
        }
        /* new content end */
        const ob = new MutationObserver(run)
        ob.observe(document.body, { attributes: true })
        document.body.setAttribute('lpromise', 'layouwen')
      }
      then(onResolve, onReject) {
        /* new content start */
        return new LPromise((resolve, reject) => {
          const cbResolve = () => {
            onResolve && onResolve()
            resolve()
          }
          this.cbResolveQueue.push(cbResolve)
          const cbReject = () => {
            onReject && onReject()
            reject()
          }
          this.cbRejectQueue.push(cbReject)
        })
        /* new content end */
      }
    }
    const l1 = new LPromise((resolve, reject) => resolve())
    l1.then(
      res => console.log('res'),
      err => console.log('err')
    ).then(
      res => console.log('res'),
      err => console.log('err')
    )
    

    此时我们已经完成了链式调用,但是我们会发现,此时如果返回一个新的 Promise ,却无法获取 Promise 的结果。所以我们得加一些判断条件。我们也会发现,此时此刻我们无法接收到 reserr 的参数。所以我们也要完善一下参数传递问题。

    class LPromise {
      constructor(callbackFn) {
        this['[[PromiseState]]'] = 'pending'
        this['[[PromiseResult]]'] = undefined
        this.cbResolveQueue = []
        this.cbRejectQueue = []
        callbackFn(this.#resolve.bind(this), this.#reject.bind(this))
      }
      #resolve(res) {
        this['[[PromiseState]]'] = 'fulfilled'
        this['[[PromiseResult]]'] = res
        const run = () => {
          let cbFn
          while ((cbFn = this.cbResolveQueue.shift())) {
            /* new content start */
            cbFn && cbFn(res)
            /* new content end */
          }
        }
        const ob = new MutationObserver(run)
        ob.observe(document.body, { attributes: true })
        document.body.setAttribute('lpromise', 'layouwen')
      }
      #reject(err) {
        this['[[PromiseState]]'] = 'reject'
        this['[[PromiseResult]]'] = err
        const run = () => {
          let cbFn
          while ((cbFn = this.cbRejectQueue.shift())) {
            /* new content start */
            cbFn && cbFn(err)
            /* new content end */
          }
        }
        const ob = new MutationObserver(run)
        ob.observe(document.body, { attributes: true })
        document.body.setAttribute('lpromise', 'layouwen')
      }
      then(onResolve, onReject) {
        return new LPromise((resolve, reject) => {
          /* new content start */
          const cbResolve = res => {
            const resolveRes = onResolve && onResolve(res)
            if (resolveRes instanceof LPromise) {
              resolveRes.then(resolve)
            } else {
              resolve(res)
            }
          }
          /* new content end */
          this.cbResolveQueue.push(cbResolve)
          /* new content start */
          const cbReject = err => {
            onReject && onReject(err)
            reject(err)
          }
          /* new content end */
          this.cbRejectQueue.push(cbReject)
        })
      }
    }
    const l1 = new LPromise((resolve, reject) => resolve('我是传入的 resolve 数据'))
    l1.then(
      res => {
        console.log('第一个then的res', res)
        return new LPromise((resolve, reject) => resolve('返回的Promise'))
      },
      err => console.log('第一个then的err', err)
    )
      .then(
        res => console.log('第二个then的res', res),
        err => console.log('第二个then的err', err)
      )
      .then(
        res => console.log('第三个then的res', res),
        err => console.log('第三个then的err', err)
      )
    

    到现在我们已经实现了 then 的链式调用

    5、实现 catch 方法

    此处代码,点击这里

    在调用 catch 的时候自动在回调队列中添加一个错误回调函数。

    class LPromise {
      constructor(callbackFn) {
        this['[[PromiseState]]'] = 'pending'
        this['[[PromiseResult]]'] = undefined
        this.cbResolveQueue = []
        this.cbRejectQueue = []
        callbackFn(this.#resolve.bind(this), this.#reject.bind(this))
      }
      #resolve(res) {
        this['[[PromiseState]]'] = 'fulfilled'
        this['[[PromiseResult]]'] = res
        const run = () => {
          let cbFn
          while ((cbFn = this.cbResolveQueue.shift())) {
            cbFn && cbFn(res)
          }
        }
        const ob = new MutationObserver(run)
        ob.observe(document.body, { attributes: true })
        document.body.setAttribute('lpromise', 'layouwen')
      }
      #reject(err) {
        this['[[PromiseState]]'] = 'reject'
        this['[[PromiseResult]]'] = err
        const run = () => {
          let cbFn
          while ((cbFn = this.cbRejectQueue.shift())) {
            cbFn && cbFn(err)
          }
        }
        const ob = new MutationObserver(run)
        ob.observe(document.body, { attributes: true })
        document.body.setAttribute('lpromise', 'layouwen')
      }
      then(onResolve, onReject) {
        return new LPromise((resolve, reject) => {
          const cbResolve = res => {
            const resolveRes = onResolve && onResolve(res)
            if (resolveRes instanceof LPromise) {
              resolveRes.then(resolve)
            } else {
              resolve(res)
            }
          }
          this.cbResolveQueue.push(cbResolve)
          const cbReject = err => {
            onReject && onReject(err)
            reject(err)
          }
          this.cbRejectQueue.push(cbReject)
        })
      }
      /* new content start */
      catch(err) {
        this.then(undefined, err)
      }
      /* new content end */
    }
    const p1 = new LPromise((resolve, reject) => reject('我是p1的错误信息'))
    p1.then(res => console.log(res)).catch(err => console.log(err))
    

    6、resolve 和 reject 静态方法

    此处代码,点击这里

    这两个静态方法比较简单。只需要返回一个固定状态的 Promise 即可。

    class LPromise {
      constructor(callbackFn) {
        this['[[PromiseState]]'] = 'pending'
        this['[[PromiseResult]]'] = undefined
        this.cbResolveQueue = []
        this.cbRejectQueue = []
        callbackFn(this.#resolve.bind(this), this.#reject.bind(this))
      }
      #resolve(res) {
        this['[[PromiseState]]'] = 'fulfilled'
        this['[[PromiseResult]]'] = res
        const run = () => {
          let cbFn
          while ((cbFn = this.cbResolveQueue.shift())) {
            cbFn && cbFn(res)
          }
        }
        const ob = new MutationObserver(run)
        ob.observe(document.body, { attributes: true })
        document.body.setAttribute('lpromise', 'layouwen')
      }
      #reject(err) {
        this['[[PromiseState]]'] = 'reject'
        this['[[PromiseResult]]'] = err
        const run = () => {
          let cbFn
          while ((cbFn = this.cbRejectQueue.shift())) {
            cbFn && cbFn(err)
          }
        }
        const ob = new MutationObserver(run)
        ob.observe(document.body, { attributes: true })
        document.body.setAttribute('lpromise', 'layouwen')
      }
      then(onResolve, onReject) {
        return new LPromise((resolve, reject) => {
          const cbResolve = res => {
            const resolveRes = onResolve && onResolve(res)
            if (resolveRes instanceof LPromise) {
              resolveRes.then(resolve)
            } else {
              resolve(res)
            }
          }
          this.cbResolveQueue.push(cbResolve)
          const cbReject = err => {
            onReject && onReject(err)
            reject(err)
          }
          this.cbRejectQueue.push(cbReject)
        })
      }
      /* new content start */
      static resolve(res) {
        return new LPromise(resolve => resolve(res))
      }
      static reject(err) {
        return new LPromise((undefined, reject) => reject(err))
      }
      /* new content end */
    }
    const p1 = LPromise.resolve('成功')
    console.log(p1)
    const p2 = LPromise.reject('失败')
    console.log(p2)
    

    7、实现 finally 方法

    此处代码,点击这里

    这个与 catch 类似的实现,只需要保证不管成功还是失败都执行里面的回调。

    class LPromise {
      constructor(callbackFn) {
        this['[[PromiseState]]'] = 'pending'
        this['[[PromiseResult]]'] = undefined
        this.cbResolveQueue = []
        this.cbRejectQueue = []
        callbackFn(this.#resolve.bind(this), this.#reject.bind(this))
      }
      #resolve(res) {
        this['[[PromiseState]]'] = 'fulfilled'
        this['[[PromiseResult]]'] = res
        const run = () => {
          let cbFn
          while ((cbFn = this.cbResolveQueue.shift())) {
            cbFn && cbFn(res)
          }
        }
        const ob = new MutationObserver(run)
        ob.observe(document.body, { attributes: true })
        document.body.setAttribute('lpromise', 'layouwen')
      }
      #reject(err) {
        this['[[PromiseState]]'] = 'reject'
        this['[[PromiseResult]]'] = err
        const run = () => {
          let cbFn
          while ((cbFn = this.cbRejectQueue.shift())) {
            cbFn && cbFn(err)
          }
        }
        const ob = new MutationObserver(run)
        ob.observe(document.body, { attributes: true })
        document.body.setAttribute('lpromise', 'layouwen')
      }
      then(onResolve, onReject) {
        return new LPromise((resolve, reject) => {
          const cbResolve = res => {
            const resolveRes = onResolve && onResolve(res)
            if (resolveRes instanceof LPromise) {
              resolveRes.then(resolve)
            } else {
              resolve(res)
            }
          }
          this.cbResolveQueue.push(cbResolve)
          const cbReject = err => {
            onReject && onReject(err)
            reject(err)
          }
          this.cbRejectQueue.push(cbReject)
        })
      }
      catch(err) {
        this.then(undefined, err)
      }
      /* new content start */
      finally(callback) {
        this.then(callback, callback)
      }
      /* new content end */
      static resolve(res) {
        return new LPromise(resolve => resolve(res))
      }
      static reject(err) {
        return new LPromise((undefined, reject) => reject(err))
      }
    }
    const p1 = new LPromise((resolve, reject) => reject('我是p1的错误信息'))
    p1.then(
      res => console.log(res),
      err => console.log(err)
    ).finally(() => console.log('finally'))
    

    8、实现 race 方法

    此处代码,点击这里

    race 就是返回最先执行成功的结果。不管是成功还是失败。这样我们只需要遍历该 Promise ,正常返回数据。谁先执行完成,谁先返回即可。注意要控制状态,防止返回多个结果。 race 只需要返回最快的一个结果。

    class LPromise {
      constructor(callbackFn) {
        this['[[PromiseState]]'] = 'pending'
        this['[[PromiseResult]]'] = undefined
        this.cbResolveQueue = []
        this.cbRejectQueue = []
        callbackFn(this.#resolve.bind(this), this.#reject.bind(this))
      }
      #resolve(res) {
        this['[[PromiseState]]'] = 'fulfilled'
        this['[[PromiseResult]]'] = res
        const run = () => {
          let cbFn
          while ((cbFn = this.cbResolveQueue.shift())) {
            cbFn && cbFn(res)
          }
        }
        const ob = new MutationObserver(run)
        ob.observe(document.body, { attributes: true })
        document.body.setAttribute('lpromise', 'layouwen')
      }
      #reject(err) {
        this['[[PromiseState]]'] = 'reject'
        this['[[PromiseResult]]'] = err
        const run = () => {
          let cbFn
          while ((cbFn = this.cbRejectQueue.shift())) {
            cbFn && cbFn(err)
          }
        }
        const ob = new MutationObserver(run)
        ob.observe(document.body, { attributes: true })
        document.body.setAttribute('lpromise', 'layouwen')
      }
      then(onResolve, onReject) {
        return new LPromise((resolve, reject) => {
          const cbResolve = res => {
            const resolveRes = onResolve && onResolve(res)
            if (resolveRes instanceof LPromise) {
              resolveRes.then(resolve)
            } else {
              resolve(res)
            }
          }
          this.cbResolveQueue.push(cbResolve)
          const cbReject = err => {
            onReject && onReject(err)
            reject(err)
          }
          this.cbRejectQueue.push(cbReject)
        })
      }
      catch(err) {
        this.then(undefined, err)
      }
      finally(callback) {
        this.then(callback, callback)
      }
      static resolve(res) {
        return new LPromise(resolve => resolve(res))
      }
      static reject(err) {
        return new LPromise((undefined, reject) => reject(err))
      }
      /* new content start */
      static race(promiseArr) {
        return new LPromise((resolve, reject) => {
          let isContinue = true
          promiseArr.forEach(promise => {
            promise.then(
              res => {
                if (isContinue) {
                  isContinue = false
                  resolve(res)
                }
              },
              err => {
                if (isContinue) {
                  isContinue = false
                  reject(err)
                }
              }
            )
          })
        })
      }
      /* new content end */
    }
    const p1 = new LPromise((resolve, reject) => setTimeout(() => resolve(1), 200))
    const p2 = new LPromise((resolve, reject) => setTimeout(() => reject(2), 1000))
    const p3 = new LPromise((resolve, reject) => setTimeout(() => resolve(3), 3000))
    LPromise.race([p1, p2, p3]).then(
      res => console.log('res', res),
      err => console.log('err', err)
    )
    

    9、实现 all 方法

    此处代码,点击这里

    all 方法当所有 Promise 都成功时返回所有结果的数组,否则返回第一个失败的结果。我们只需要遍历该 Promise 数组。定义个变量存放当前 res 的长度。如果长度等于数组的长度,我们就 resolve 出去。否则发现第一个失败的时候,直接 reject

    class LPromise {
      constructor(callbackFn) {
        this['[[PromiseState]]'] = 'pending'
        this['[[PromiseResult]]'] = undefined
        this.cbResolveQueue = []
        this.cbRejectQueue = []
        callbackFn(this.#resolve.bind(this), this.#reject.bind(this))
      }
      #resolve(res) {
        this['[[PromiseState]]'] = 'fulfilled'
        this['[[PromiseResult]]'] = res
        const run = () => {
          let cbFn
          while ((cbFn = this.cbResolveQueue.shift())) {
            cbFn && cbFn(res)
          }
        }
        const ob = new MutationObserver(run)
        ob.observe(document.body, { attributes: true })
        document.body.setAttribute('lpromise', 'layouwen')
      }
      #reject(err) {
        this['[[PromiseState]]'] = 'reject'
        this['[[PromiseResult]]'] = err
        const run = () => {
          let cbFn
          while ((cbFn = this.cbRejectQueue.shift())) {
            cbFn && cbFn(err)
          }
        }
        const ob = new MutationObserver(run)
        ob.observe(document.body, { attributes: true })
        document.body.setAttribute('lpromise', 'layouwen')
      }
      then(onResolve, onReject) {
        return new LPromise((resolve, reject) => {
          const cbResolve = res => {
            const resolveRes = onResolve && onResolve(res)
            if (resolveRes instanceof LPromise) {
              resolveRes.then(resolve)
            } else {
              resolve(res)
            }
          }
          this.cbResolveQueue.push(cbResolve)
          const cbReject = err => {
            onReject && onReject(err)
            reject(err)
          }
          this.cbRejectQueue.push(cbReject)
        })
      }
      catch(err) {
        this.then(undefined, err)
      }
      finally(callback) {
        this.then(callback, callback)
      }
      static resolve(res) {
        return new LPromise(resolve => resolve(res))
      }
      static reject(err) {
        return new LPromise((undefined, reject) => reject(err))
      }
      static race(promiseArr) {
        return new LPromise((resolve, reject) => {
          let isContinue = true
          promiseArr.forEach(promise => {
            promise.then(
              res => {
                if (isContinue) {
                  isContinue = false
                  resolve(res)
                }
              },
              err => {
                if (isContinue) {
                  isContinue = false
                  reject(err)
                }
              }
            )
          })
        })
      }
      /* new content start */
      static all(promiseArr) {
        return new LPromise((resolve, reject) => {
          const resArr = []
          const length = promiseArr.length
          promiseArr.forEach(p => {
            p.then(
              res => {
                resArr.push(res)
                if (resArr.length === length) {
                  resolve(resArr)
                }
              },
              err => reject(err)
            )
          })
        })
      }
      /* new content end */
    }
    const p1 = new LPromise((resolve, reject) => setTimeout(() => resolve(1), 200))
    const p2 = new LPromise((resolve, reject) => setTimeout(() => reject(2), 1000))
    const p3 = new LPromise((resolve, reject) => setTimeout(() => reject(3), 3000))
    LPromise.all([p1, p2, p3]).then(
      res => console.log('res', res),
      err => console.log('err', err)
    )
    

    10、实现 allSettled 方法

    此处代码,点击这里

    该方法与 all 类似。只是这个方法不管成功或失败,只要该 Promise 数组执行完毕。就会返回所有结果。我们只需要判断执行过的 Promise 长度是否等于数组长度。当一致时就直接 resolve。并且每次执行的时候,将返回值以指定格式的对象保存到返回的 res 中。

    class LPromise {
      constructor(callbackFn) {
        this['[[PromiseState]]'] = 'pending'
        this['[[PromiseResult]]'] = undefined
        this.cbResolveQueue = []
        this.cbRejectQueue = []
        callbackFn(this.#resolve.bind(this), this.#reject.bind(this))
      }
      #resolve(res) {
        this['[[PromiseState]]'] = 'fulfilled'
        this['[[PromiseResult]]'] = res
        const run = () => {
          let cbFn
          while ((cbFn = this.cbResolveQueue.shift())) {
            cbFn && cbFn(res)
          }
        }
        const ob = new MutationObserver(run)
        ob.observe(document.body, { attributes: true })
        document.body.setAttribute('lpromise', 'layouwen')
      }
      #reject(err) {
        this['[[PromiseState]]'] = 'reject'
        this['[[PromiseResult]]'] = err
        const run = () => {
          let cbFn
          while ((cbFn = this.cbRejectQueue.shift())) {
            cbFn && cbFn(err)
          }
        }
        const ob = new MutationObserver(run)
        ob.observe(document.body, { attributes: true })
        document.body.setAttribute('lpromise', 'layouwen')
      }
      then(onResolve, onReject) {
        return new LPromise((resolve, reject) => {
          const cbResolve = res => {
            const resolveRes = onResolve && onResolve(res)
            if (resolveRes instanceof LPromise) {
              resolveRes.then(resolve)
            } else {
              resolve(res)
            }
          }
          this.cbResolveQueue.push(cbResolve)
          const cbReject = err => {
            onReject && onReject(err)
            reject(err)
          }
          this.cbRejectQueue.push(cbReject)
        })
      }
      catch(err) {
        this.then(undefined, err)
      }
      finally(callback) {
        this.then(callback, callback)
      }
      static resolve(res) {
        return new LPromise(resolve => resolve(res))
      }
      static reject(err) {
        return new LPromise((undefined, reject) => reject(err))
      }
      static race(promiseArr) {
        return new LPromise((resolve, reject) => {
          let isContinue = true
          promiseArr.forEach(promise => {
            promise.then(
              res => {
                if (isContinue) {
                  isContinue = false
                  resolve(res)
                }
              },
              err => {
                if (isContinue) {
                  isContinue = false
                  reject(err)
                }
              }
            )
          })
        })
      }
      static all(promiseArr) {
        return new LPromise((resolve, reject) => {
          const resArr = []
          const length = promiseArr.length
          promiseArr.forEach(p => {
            p.then(
              res => {
                resArr.push(res)
                if (resArr.length === length) {
                  resolve(resArr)
                }
              },
              err => reject(err)
            )
          })
        })
      }
      /* new content start */
      static allSettled(promiseArr) {
        return new LPromise(resolve => {
          const resArr = new Array(promiseArr.length)
          let num = 0
          promiseArr.forEach(p => {
            let obj = {}
            p.then(
              res => {
                obj.status = 'fulfilled'
                obj.value = res
                resArr[num] = obj
                num++
                if (num === resArr.length) resolve(resArr)
              },
              err => {
                obj.status = 'rejected'
                obj.reason = err
                resArr[num] = obj
                num++
                if (num === resArr.length) resolve(resArr)
              }
            )
          })
        })
      }
      /* new content end */
    }
    const p1 = new LPromise((resolve, reject) => setTimeout(() => resolve(1), 200))
    const p2 = new LPromise((resolve, reject) => setTimeout(() => reject(2), 1000))
    const p3 = new LPromise((resolve, reject) => setTimeout(() => reject(3), 3000))
    LPromise.allSettled([p1, p2, p3]).then(
      res => console.log('res', res),
      err => console.log('err', err)
    )
    

    End

    本文章实现的 Promise 不够完善,只是大概把实现原理带大家过一遍。Promise 的源码不是由 js 写的,所以我们只能尽可能使用 js 模仿。欢淫各位大佬补充更完善的版本。

    交流学习~


    起源地下载网 » 一步步实现一个Promise

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元