实现一个符合promiseA+规范的promise

前端开发Kingcean 2020-05-30

export default class Promise2 {
  state=‘pending‘
  callbacks = []

  resolve(result) {
    this.excute(‘fulfilled‘, result, 0)
  }
  reject(reason) {
    this.excute(‘rejected‘, reason, 1)
  }

  excute(state, data, i) {
    if(this.state !== ‘pending‘) return
    this.state = state
    nextTick(() => {
      this.callbacks.forEach(el => {
        if(typeof el[i] === ‘function‘) {
          let x
          try {
            x = el[i].call(undefined, data)
          } catch (error) {
            el[2].reject(error)
          }
          el[2].resolveWith(x)
        }
      })
    })
  }
  constructor(fn) {
    fn(this.resolve.bind(this), this.reject.bind(this))
  }
  then(succeed?, failed?) {
    const arr = []
    if(typeof succeed === ‘function‘) {
      arr[0] = succeed
    }
    if(typeof failed === ‘function‘) {
      arr[1] = failed
    }
    arr[2] = new Promise2(() => {})
    this.callbacks.push(arr)

    return arr[2]
  }

  resolveWithThenable(x) {
    try {
      x.then(
        y => {
          this.resolveWith(y);
        },
        r => {
          this.reject(r);
        }
      );
    } catch (e) {
      this.reject(e);
    }
  }

  resolveWith(x) {
    if (this === x) this.reject(new TypeError())
    else if (x instanceof Promise2) {
      x.then(res => {
        this.resolve(res)
      }, err => {
        this.reject(err)
      })
    } else if (x instanceof Object) {
      // if a thenable
      let then
      try {
        then = x.then
      } catch(e) {
        this.reject(e)
      }
      if (then instanceof Function) {
        this.resolveWithThenable(x)
      } else {
        this.resolve(x)
      }
    } else {
      this.resolve(x)
    }
  }
}

function nextTick(fn) {
  if(process !== undefined && typeof process.nextTick === ‘function‘) return process.nextTick(fn)
  else {
    var counter = 1
    var observer = new MutationObserver(fn)
    var textNode = document.createTextNode(String(counter))

    observer.observe(textNode, {
      characterData: true
    })

    counter = counter+1
    textNode.data = String(counter)
  }
}

相关推荐