简单实现一个Promise

Promise的构造函数

function Promise(fn){
    const self = this //在执行then注册函数时, 传入的函数中需要被this调用, 但是
    this.status = 'pending' //状态
    this.value              //值
    this.onResolvedCallback = [] //promise resolve时的回调函数集, 因为在promise结束之前有可能有多个回调添加它的上面(此处有疑问)
    this.onRejectedCallback = [] //同上
    try{ //传入的代码不确定正确性
    fn.call(this, this.resolve, this.reject) //调用传入的方法
    }catch(e){
        this.reject(e)
    }


    //resolve方法, 用于改变状态
    resolve: function(value){
        if(this.status === 'pending'){
            this.value = value
            this.status = 'resolved'
            //检查是否有状态改变的时调用可以调用的
            for(var i = 0; i < self.onResolvedCallback.length; i++){
                this.onResolvedCallback(i)[value]
            }
        }

    }
    reject: function(err){
        if(this.status === 'pending'){
            this.status = 'rejected'
            this.value = err
            //检查是否有该状态的处理函数
            for(var i = 0; i < self.onRejectedCallback.length; i++){
                self.onRejectedCallback[i](value)
            }
        }
    }
}

then方法

Promise.prototype.then = function(onResolved, onRejected) {
    var self = this
    var promise2

    //根据标准, 如果then参数不是function, 则需要忽略它, 
    onResolved = typeof onResolved === 'function' ? onResolved : function(v){return v}  //function(v){return v}可以解决穿透问题
    onReject = typeof onRejected === 'function' ? onReject : function(r){return r} 

    if (self.status === 'resolved') {
        return promise2 = new Promise(function(resolve, reject){
    //此处返回了一个新的promise对象, 接下来要根据处理函数的返回值设置新promise的值和状态
            try{
                var x = onResolved(self.value)
                if(x instanceof Promise){//如果返回值是promise对象

                    x.then(resolve, reject)//如果x是resolved状态的promise, 使用resolve调用函数,返回一个resolved状态, x.value值的promise。
                }
                //如果不是promise
                this.resolve(x)//返回一个resolved状态的promise
            }catch(e){
                this.reject(e)
            }
        })
    },

    if(self.status === 'reject'){
        return promise2 = new Promise((resovle, reject)=>{
            //根据onRejected的返回值设置状态
            try{
                var x = onRejected(self.value)
                if(x instansof Promise){
                    x.then(resolve, reject)
                }
                this.reject(x)
            }catch(e){
                this.reject(x)
            }
        })
    },

    if(self.status === 'pending'){
        return promise2 = new Promise((resolve, rejecct) ={
            //此后的状态未知, 需要等待promise1 来自己决定调用哪一个函数, 所以将这个处理函数包装一下(毕竟需要调用之后能够影响到promise2)写到promise1的回调函数中
            self.onResolvedCallback.push(function(value){
                try{
                    var x = onResolved(self.value)//传入promise的值
                    if(x instansof Promise){
                        x.then(resolve, reject) 
                    }
                    resolve(x)// 用于改变promie2的状态
                }catch(e){
                    reject(e)   
                }
            })

            self.onRejectCallback.push(function(value){
                try{
                    var x = onRejected(self.value)  
                    if(x instanceof Promise){
                        x.then(resolve, reject)
                    }
                    reject(x)
                }catch(e){
                    reject(e)
                }
            })

        })
    }

}

以上, 变完成了promise的then方法。 但是存在的一个问题: 不同Promise实现之间不能无缝的交互

思考: 在我们的代码中, 为啥不能做到不同promise实现之间不可交互?

因为: 他们互相不认识啊!且看then方法中, 因为调用then返回的是一个promise对象, 且该promise对象会根据注册的处理函数的返回值来设置自己的状态和值。 所有有一个 x instanceof Promise来判断该返回值是否是promise对象。 那么我们写的promise显然不同通过x instanceof promise来认识es6中的promise。所以标准中给出了如下代码用于不同promise实现的相互的认识。

/*
resolvePromise函数即为根据x的值来决定promise2的状态的函数
也即标准中的[Promise Resolution Procedure](https://promisesaplus.com/#point-47)
x为`promise2 = promise1.then(onResolved, onRejected)`里`onResolved/onRejected`的返回值
`resolve`和`reject`实际上是`promise2`的`executor`的两个实参,因为很难挂在其它的地方,所以一并传进来。
相信各位一定可以对照标准把标准转换成代码,这里就只标出代码在标准中对应的位置,只在必要的地方做一些解释
*/
function resolvePromise(promise2, x, resolve, reject) {
  var then
  var thenCalledOrThrow = false

  if (promise2 === x) { // 对应标准2.3.1节
    return reject(new TypeError('Chaining cycle detected for promise!'))
  }

  if (x instanceof Promise) { // 对应标准2.3.2节
    // 如果x的状态还没有确定,那么它是有可能被一个thenable决定最终状态和值的
    // 所以这里需要做一下处理,而不能一概的以为它会被一个“正常”的值resolve
    if (x.status === 'pending') {
      x.then(function(value) {
        resolvePromise(promise2, value, resolve, reject)
      }, reject)
    } else { // 但如果这个Promise的状态已经确定了,那么它肯定有一个“正常”的值,而不是一个thenable,所以这里直接取它的状态
      x.then(resolve, reject)
    }
    return
  }

  if ((x !== null) && ((typeof x === 'object') || (typeof x === 'function'))) { // 2.3.3
    try {

      // 2.3.3.1 因为x.then有可能是一个getter,这种情况下多次读取就有可能产生副作用
      // 即要判断它的类型,又要调用它,这就是两次读取
      then = x.then 
      if (typeof then === 'function') { // 2.3.3.3
        then.call(x, function rs(y) { // 2.3.3.3.1
          if (thenCalledOrThrow) return // 2.3.3.3.3 即这三处谁选执行就以谁的结果为准
          thenCalledOrThrow = true
          return resolvePromise(promise2, y, resolve, reject) // 2.3.3.3.1
        }, function rj(r) { // 2.3.3.3.2
          if (thenCalledOrThrow) return // 2.3.3.3.3 即这三处谁选执行就以谁的结果为准
          thenCalledOrThrow = true
          return reject(r)
        })
      } else { // 2.3.3.4
        resolve(x)
      }
    } catch (e) { // 2.3.3.2
      if (thenCalledOrThrow) return // 2.3.3.3.3 即这三处谁选执行就以谁的结果为准
      thenCalledOrThrow = true
      return reject(e)
    }
  } else { // 2.3.4
    resolve(x)
  }
}

然后使用这个函数的调用代替then里几处判断x是否为promise的位置即可。

 if (self.status === 'rejected') {
    return promise2 = new Promise(function(resolve, reject) {
      setTimeout(function() { // 异步执行onRejected
        try {
          var x = onRejected(self.data)
          resolvePromise(promise2, x, resolve, reject)
        } catch (reason) {
          reject(reason)
        }
      })
    })

then方法的流程图

这里写图片描述

文本是阅读了该文, 并根据自己的理解所写, 经过了第二次消化, 如有不懂之处, 建议看看这篇文章

猜你喜欢

转载自blog.csdn.net/qq_34178990/article/details/81078906
今日推荐