Promise

难点:

  1. 异步处理
  2. 兼容不同 PromiseresolvePromise 函数
interface MyPromise {
  status: 'pendding' | 'resloved' | 'rejected'
  data: any
  onResolvedCallback: Array<Function>
  onRejectedCallback: Array<Function>


  then: (onFulfill?: any, onReject?: any) => void

  catch: (reason: any) => void

  resolve: (val: any) => Promise

  reject: (reason: any) => Promise

  all: (promises: Array) => Promise

  race: (promises: Array) => Promise
}


class Promise implements MyPromise {
  private status
  private data
  private onResolvedCallback
  private onRejectedCallback

  constructor(executor?: Function) {
    this.status = 'pendding'

    this.onResolvedCallback = []
    this.onRejectedCallback = []

    const resolve = (value) => {
      if (value instanceof Promise) {
        return value.then(resolve, reject)
      }

      setTimeout(() => {
        if (this.status === 'pendding') {
          this.status = 'resloved'
          this.data = value
          this.onResolvedCallback.forEach((fn) => fn(value))
        }
      })
    }

    const reject = (reason) => {
      setTimeout(() => {
        if (this.status === 'pendding') {
          this.status = 'rejected'
          this.data = reason
          this.onRejectedCallback.forEach((fn) => fn(reason))
        }
      })
    }

    try {
      executor(resolve, reject)
    } catch (e) {
      this.catch(e)
    }
  }

  public then(onFulfill, onReject) {
    const self = this
    let promise2
    onFulfill = typeof onFulfill === 'function' ? onFulfill : (v) => v
    onReject = typeof onReject === 'function' ? onReject : (v) => {
      throw v
    }

    if (self.status === 'resolved') {
      return promise2 = new Promise(function (resolve, reject) {
        try {
          var x = onFulfill(self.data)
          if (x instanceof Promise) {
            x.then(resolve, reject)
          }
          resolve(x)
        } catch (e) {
          reject(e)
        }
      })
    }

    if (self.status === 'rejected') {
      return promise2 = new Promise(function (resolve, reject) {
        try {
          var x = onReject(self.data)
          if (x instanceof Promise) {
            x.then(resolve, reject)
          }
        } catch (e) {
          reject(e)
        }
      })
    }

    if (self.status === 'pendding') {
      promise2 = new Promise((resolve, reject) => {
        self.onResolvedCallback.push((value) => {
          try {
            let x = onFulfill(value)
            resolvePromise(promise2, x, resolve, reject)
          } catch (e) {
            reject(e)
          }
        })

        self.onRejectedCallback.push((value) => {
          try {
            let x = onReject(value)
            resolvePromise(promise2, x, resolve, reject)
          } catch (e) {
            reject(e)
          }
        })
      })
    }

    return promise2
  }

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

  public resolve(val) {
    return new Promise((resolve, reject) => {
      resolve(val)
    })
  }

  public reject(reason) {
    return new Promise((resolve, reject) => {
      reject(reason)
    })
  }

  public all(promises) {
    let datas = []
    let len = 0

    function processData(data, index, resolve) {
      len += 1
      datas[index] = data
      if (len === promises.length) {
        resolve(datas)
      }
    }

    return new Promise((resolve, reject) => {
      promises.forEach((promise, index) => {
        if (promise instanceof Promise) {
          promise.then((data) => processData(data, index, resolve))
        } else {
          this.resolve(promise).then((data) => processData(data, index, resolve))
        }
      })
    })
  }

  public race(promises) {
    return new Promise((resolve, reject) => {
      promises.forEach((promise, index) => {
        if (promise instanceof Promise) {
          promise.then(resolve, reject)
        } else {
          this.resolve(promise).then(resolve, reject)
        }
      })
    })
  }
}

function resolvePromise(promise2: Function, x: Function, resolve: Function, reject: Function): void {
  var then
  var thenCalledOrThrow = false

  if (promise2 === x) {
    return reject(new TypeError('Chaining cycle detected for promise!'))
  }

  if (x instanceof Promise) {
    if (x.status === 'pendding') {
      x.then(function (v) {
        resolvePromise(promise2, v, resolve, reject)
      }, reject)
    } else {
      x.then(resolve, reject)
    }
    return
  }

  if ((x !== null) && ((typeof x === 'object') || (typeof x === 'function'))) {
    try {
      then = x.then
      if (typeof then === 'function') {
        then.call(x, function rs(y) {
          if (thenCalledOrThrow) return
          thenCalledOrThrow = true
          return resolvePromise(promise2, y, resolve, reject)
        }, function rj(r) {
          if (thenCalledOrThrow) return
          thenCalledOrThrow = true
          return reject(r)
        })
      } else {
        resolve(x)
      }
    } catch (e) {
      if (thenCalledOrThrow) return
      thenCalledOrThrow = true
      return reject(e)
    }
  } else {
    resolve(x)
  }
}

参考

Promise之你看得懂的Promise

剖析Promise内部结构