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

实现promiseA+规范时有几个思考点值得注意:

  1. then方法的作用是什么?
    then(succeed, failed)内部其实就是将succeed和failed这两个处理成功和失败的回调函数和then执行后生成的新promise对象push进callbacks[] 这个数组里。
  2. 如何让then方法返回一个promise(实现链式调用)?
    在callbacks里找到成功或失败的回调,call调用他们,记录结果然后在生成的新promise里手动resolve这个结果。
  3. then(succeed, failed) 中的succeed和failed有返回值x,x可能是哪些值?分别该作何处理?如果在succeed和failed执行时出现了异常该如何处理?
    具体说明在promiseA+规范的2.3章节。x可能是promise对象自身,可能是一个新的promise对象,或者一个对象,一个函数,一个thenable,或者其他简单类型。
  4. 如何模拟一个微任务?
    settimeout是宏任务,而then则是微任务,在node环境可以使用process.nextTick(),而在浏览器环境则使用MutationObserver来代替。

这些问题其实在promiseA+规范中已经讲清楚了,所以只要按照规范写出测试用例,进而写出满足测试用例的代码,就实现了一个符合规范的Promise。

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)
  }
}

posted @ 2020-05-30 14:05  zjy960816  阅读(238)  评论(0)    收藏  举报