1. 程式人生 > >手動實現一個Promise

手動實現一個Promise

ES6中實現的Promise是 Promise/A+ 規範。
首先,有三種狀態:pending ,fulfilled, rejected。

    const PENDING = 'PENDING'
    const FULFILLED = 'FULFILLED'
    const REJECTED = 'REJECTED'
    const isFunction = x => typeof x === 'function'

    class MyPromise {
      constructor(handler) {
        if (!isFunction(handler)) throw new Error('must a parms')
        this._value = undefined
        this._status = PENDING
        
        this._filfilledQueues = []
        this._rejectedQueues = []

        try {
          handler(this._resolve.bind(this), this._reject.bind(this))
        } catch (err) {
          this._reject(err)
        }
      }

      _resolve(val) {
        if (this._status !== PENDING) return
        setTimeout(() => {
          this._status = FULFILLED
          this._value = val
          this._filfilledQueues.forEach(item => item(val))
        }, 0)
      }

      _reject(err) {
        if (this._status !== PENDING) return
        this._status = REJECTED
        this._value = err

        this._rejectedQueues.forEach(item => item())
      }

      then(onFulfilled, onRejected) {
        const { _value, _status } = this

        return new MyPromise((onFulfilledNext, onRejectedNext) => {

          let fulfilled = value => {
            try {
              if (!isFunction(onFulfilled)) {
                onFulfilledNext(value)
              } else {
                let res = onFulfilled(value)
                if (res instanceof MyPromise) {
                  res.then(onFulfilledNext, onRejectedNext)
                } else {
                  onFulfilledNext(res)
                }
              }
            } catch (err) {
              onRejectedNext(err)
            }
          }

          let rejected = error => {
            try {
              if (!isFunction(onRejected)) {
                onRejectedNext(error)
              } else {
                let res = onRejected(error)
                if (res instanceof MyPromise) {
                  res.then(onFulfilledNext, onRejectedNext)
                } else {
                  onFulfilledNext(res)
                }
              }
            } catch (err) {
              onRejectedNext(err)
            }
          }
          
          switch (_status) {
            case PENDING:
              this._filfilledQueues.push(fulfilled)
              this._rejectedQueues.push(rejected)
              break
            case FULFILLED:
              fulfilled(_value)
              break
            case REJECTED:
              rejected(_value)
              break
          }
        })
      }

      catch(onRejected) {
        return this.then(null, onRejected)
      }

      static all(arr) {
        return new MyPromise((resolve, reject) => {
          let values = []
          let count = 0
          for (let [i, p] of arr.entries()) {
            this.resolve(p).then(res => {
              values[i] = res
              count++

              if (count === arr.length) {
                resolve(values)
              }
            }, err => {
              reject(err)
            })
          }
        })
      }

      static race(arr) {
        return new MyPromise((resolve, reject) => {
          for (let p of arr) {
            this.resolve(p).then(res => {
              resolve(res)
            }, err => {
              reject(err)
            })
          }
        })
      }
    }