手写一个Promise

经常在面试题中会看到,让你实现一个Promsie,或者问你实现Promise的原理,所以今天就尝试利用class类的形式来实现一个Promise
为了不与原生的Promise命名冲突,这里就简单命名为MyPromise.

class Promise {
  constructor(executor) {
    const self = this
    self.state = 'pending'
    self.value = null
    self.reason = null
    self.onFulfilledFunc = []
    self.onRejectedFunc = []

    function resolve(value) {
      if (self.state === 'pending') {
        self.value = value
        self.state = 'resolved'
        self.onFulfilledFunc.forEach(fn => fn(value))
      }
    }

    function reject(reason) {
      if (self.state === 'pending') {
        self.reason = reason
        self.state = 'rejected'
        self.onRejectedFunc.forEach(fn => fn(reason))
      }
    }

    try {
      executor(resolve, reject)
    } catch (error) {
      reject(error)
    }
  }
  then(onFulfilled, onRejected) {
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : val => val
    onRejected =
      typeof onRejected === 'function'
        ? onRejected
        : err => {
            throw err
          }
    let self = this
    let promise2
    switch (self.state) {
      case 'resolved':
        promise2 = new Promise((resolve, reject) => {
          setTimeout(() => {
            try {
              let x = onFulfilled(self.value)
              resolvePromise(promise2, x, resolve, reject)
            } catch (e) {
              reject(e)
            }
          }, 0)
        })
        break
      case 'rejected':
        promise2 = new Promise((resolve, reject) => {
          setTimeout(() => {
            try {
              let x = onRejected(self.reason)
              resolvePromise(promise2, x, resolve, reject)
            } catch (e) {
              reject(e)
            }
          }, 0)
        })
        break
      case 'pending':
        promise2 = new Promise((resolve, reject) => {
          self.onFulfilledFunc.push(() => {
            setTimeout(() => {
              try {
                let x = onFulfilled(self.value)
                resolvePromise(promise2, x, resolve, reject)
              } catch (e) {
                reject(e)
              }
            }, 0)
          })
          self.onRejectedFunc.push(() => {
            setTimeout(() => {
              try {
                let x = onRejected(self.reason)
                resolvePromise(promise2, x, resolve, reject)
              } catch (e) {
                reject(e)
              }
            }, 0)
          })
        })
        break
      default:
        break
    }
    return promise2
  }
  catch(onRejected) {
    return this.then(null, onRejected)
  }
  finally(fn) {
    this.then(() => {
      fn()
    }, () => {
      fn()
    })
    return this
  }
  static resolve(value) {
    return new Promise(resolve => {
      resolve(value)
    })
  }
  static reject(reason) {
    return new Promise(reject => {
      reject(reason)
    })
  }
  static all(values) {
    return new Promise((resolve, reject) => {
      const result = []
      let index = 0
      function keyToArr(key, value) {
        index++
        result[key] = value
        if (index === values.length) {
          resolve(result)
        }
      }

      for (let i = 0; i < values.length; i++) {
        let current = values[i]
        if (current !== null && (typeof current === 'object' || typeof current === 'function')) {
          let then = current.then
          if (typeof then === 'function') {
            then(value => {
              keyToArr(i, value)
            }, e => {
              reject(e)
            })
          } else {
            keyToArr(i, current)
          }
        } else {
          keyToArr(i, current)
        }
      }
    })
  }
  static race(values) {
    return new Promise((resolve, reject) => {
      for (let i = 0; i < values.length; i++) {
        const current = values[i]
        if (current !== null && (typeof current === 'object' || typeof current === 'function')) {
          let then = current.then
          if (typeof then === 'function') {
            then(resolve, reject)
          } else {
            resolve(current)
          }
        } else {
          resolve(current)
        }
      }
    })
  }
  static deferred() {
    let dfd = {}
    dfd.promise = new Promise((resolve, reject) => {
      dfd.resolve = resolve
      dfd.reject = reject
    })
    return dfd
  }
}

function resolvePromise(promise2, x, resolve, reject) {
  if (promise2 === x) {
    return reject(new TypeError('Promise循环引用'))
  }
  let isUsed // 确保resolve或者rejected后,状态不会再次发生变更
  if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
    try {
      let then = x.then
      if (typeof then === 'function') {
        then.call(x, y => {
          if (isUsed) return
          isUsed = true
          resolvePromise(promise2, y, resolve, reject)
        }, e => {
            if (isUsed) return
            isUsed = true
          reject(e)
        })
      } else {
        if (isUsed) return
        isUsed = true
        resolve(x)
      }
    } catch (e) {
      if (isUsed) return
      isUsed = true
      reject(e)
    }
  } else {
    resolve(x)
  }
}

module.exports = Promise

检测是否完全符合Promise/A+规范

npm install -g promises-aplus-tests 

具体用法请看promise test然后

promises-aplus-tests  myPromise.js

结果真香:
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值