手写Promise笔记(下)

在手写Promise笔记(上)我们已经得到了一个可用的手写Promise,不过过一阵子再来看,还是发现有很多地方不记得了,下面补上结合手写代码的Promise用法以及图解,加强记忆。

都是个人理解如果有错误,欢迎提出

Promise的基本用法

new myPromise((resolve, reject) => {
   resolve("成功");
}).then(
  msg => {
    console.log(msg);
  },
  error => {
    console.log(error);
  }
);

上面的代码是一个最普通的Promise用法then方法中对应的第一个是onFulfilled方法,第二个是onRejected方法。此时Promise的内部代码是同步的,resolve("成功")会直接更改,当前Promise的状态,在then方法会执行以下代码

      let promise =  new myPromise((resolve,reject) => {
         if(this.status === myPromise.PENDING) {
         ......
         }
         // 这里判断状态,必须是解决状态的情况才会执行onFulfilled函数,否则会出现状态没改变也执行的情况
         if(this.status === myPromise.FULFILLED) {
            setTimeout(() => {
               this.parse(promise,onFulfilled(this.value),resolve,reject)
            }, 0)
         }
         if(this.status === myPromise.REJECT) {
         ......
         }
      })
      return promise
   }

会把当前返回的promise以及传入的onFulfilled,这里的resolve以及reject都是新new出来的Promise自带的。在parse函数中会做以下的处理

   parse(promise,result,resolve,reject) {
      if(promise === result) {
         // 这里的判断用于限制Promise.then不能返回自身
         throw new TypeError('aaa')
      }
      // 使用try..catch也是为了捕获then中出现的错误,只有写了catch才会有错误信息输出
      try {
           // 这里的更改主要是针对Promise的内部函数的异步处理
           // 通过instanceof来判断result是否是通过myPromise实现的,从而确定是否是返回的Promise
           if (result instanceof myPromise) {
              // 如果是Promise的话,目的还是要改变Promise的状态,并且返回值
              // 此时 result 是一个Promise
              // 这里相当于重新执行了一次返回的Promise,递归
              result.then(resolve,reject)
           } else {
              // 普通值直接返回
              resolve(result)
           }
        } catch (error) {
           // then的异步处理中出现error就交给onRejected处理
           // 同时这里的处理函数从onRejected改为reject,相当于把错误代码交给了
           // 最后一个then来处理
           reject(error)
        }
   }
parse函数

这样上面那个最简单的Promise的使用就相当于

  1. resolve("成功"),变更当前Promise的状态为fulfilled,函数内的setTimeout异步函数挂起
  2. 进入then方法,此时的状态为fulfilled,所以进入this.parse(promise,onFulfilled(this.value),resolve,reject)代码,因为当前的onFulfilled方法为一个简单的打印,不是返回Promise,那么就直接使用新返回的Promiseresolve方法执行,此时的this.value='成功',那么就相当于调用msg => {console.log(msg)},之前resolve挂起的定时器异步任务开始执行,callback为空,所以无结果。
    相当于then中最后执行的结果如下
let promise = new myPromise((resolve,reject) => {
  setTimeout(() => {
    this.parse(promise,onFulfilled(this.value),resolve,reject)
   }, 0)
})
return promise 

这里我不太清楚,返回的Promiseparse之间的运行关系,希望以后有机会找大佬请教下

Promise内的异步操作

假设Promise内的操作是异步的,这种情况还是挺常见的,例如异步获取数据之类的。

let p = new myPromise((resolve, reject) => {
  setTimeout(() => {
    resolve("成功")
  }, 0);
}).then(
  msg => {
    console.log('promise' + msg);
  },
  error => {
    console.log(error);
  }
)
console.log('我先执行')

输出的结果是我先执行---promise成功
这里就会涉及到JavaScript中的EvenLoop,直接看手写代码,这里只解释成功的部分,失败的部分原理一样。
在resolve方法中

   resolve(value) {
      // 这里需要增加一个判断,如果当前Promise的状态为pending的时候,才能进行状态更改和处理
      if(this.status === myPromise.PENDING) {
        this.status = myPromise.FULFILLED
        this.value = value
        setTimeout(() => {
           this.callbacks.map(callback => {
            callback.onFulfilled(value)
         })
        })
      }
   }

在then方法中

if(this.status === myPromise.PENDING) {
            this.callbacks.push({
               onFulfilled: value => {
                  this.parse(promise,onFulfilled(value),newresolve,newreject)
               },
               onRejected: reason => {
                  this.parse(promise,onRejected(reason),newresolve,newreject)
               },
            })
         }

如果Promise本体中的方法是异步的,当函数开始的时候,内部的定时器挂起,此时定时器是一个宏任务,异步执行,之后执行到then方法,方法内判断到当前的状态pending,那么就会将传入的onFulfilledonRejected通过parse处理后保存起来。
此轮同步循环结束,执行之前挂起的定时器,开始循环callback中的onFulfilled方法,并且执行,完成异步输出的结果。

Promise的链式调用

Promise链式调用的前提就是前一个then返回的是一个Promise,并且下一个then对应的状态总是成功的

let p = new myPromise((resolve, reject) => {
    // resolve("成功")
    reject("失败")
}).then(
  msg => {
    console.log('promise' + msg);
    return '成功22'
  },
  error => {
    console.log(error);
    return '失败22'
  }
)
.then(
  msg => {
    console.log('promise2' + msg);
  },
  error => {
    console.log(error);
  }
)

上面的代码无论第一个使用的是resolve还是reject,第二个then都是走console.log('promise2' + msg)


上面例子代码的运行流程

  1. 首先new myPromise的时候首先同步执行reject("失败"),此时当前Promise的状态为rejected
  2. 进入第一个then,因为判断当前状态时rejected,会执行
if(this.status === myPromise.REJECT) {
            setTimeout(() => {
               this.parse(promise,onRejected(this.value),newresolve,newreject)
            }, 0)
         }

此时setTimeout挂起第一个异步程序,这里我们把它叫做定时1

  1. 然后第一个then返回了一个新的Promise,叫做newPromise,并且通过他连接上下一个then
  2. 在这个newPromise中,resolvereject函数都没有执行,所以当前的newPromise的状态还是pending,在then中判断状态,就把第二个then中的两个函数通过parse处理后存起来。
  3. 以上同步任务都处理完成了,会进入Promise中的定时1,开始执行其中的异步程序。
 setTimeout(() => {
   this.parse(promise,onRejected(this.value),newresolve,newreject)
 }, 0)

这里的newresolvenewreject是返回的newPromise中的resolvereject函数,在parse会判断第一个then返回的onRejected是不是Promise,如果不是就用传入的newresolve来执行
相当于执行了

newresolve(msg => {
    console.log('promise' + msg);
    return '成功22'
  })
  1. newPromise的内部resolve执行的就是resolve('成功22')接受'成功22'这个参数,并且更改newPromise的状态为resolved,此时newPromise的之前保存函数callbacks也不为空了,循环执行之前保存的onFulfilled函数
  2. 上面的过程就实现了then的链式调用

then中返回一个Promise的情况

如果 then 返回的是一个promise,那么需要等这个promise,那么会等这个promise执行完,promise如果成功,就走下一个then的成功,如果失败,就走下一个then的失败。

let p2 = new myPromise((resolve,reject) => {
  reject('失败了')
})
new myPromise((resolve, reject) => {
    resolve("成功")
    // reject("失败")
}).then(
  msg => {
    console.log('promise' + msg);
    return p2
  },
  error => {
    console.log(error);
    return '失败22'
  }
)
.then(
  msg => {
    console.log('promise2' + msg);
  },
  error => {
    console.log('then2'+ error);
  }
)


这里主要通过parse来进行操作的,可以看最上面parse的全部代码这里只放部分了

if (result instanceof myPromise) {
  result.then(resolve,reject) 
} 

这里传入的result就是前一个then方法的onFulfilled(this.value)或者onRejected(this.value)

msg => {
    console.log('promise' + msg);
    return p2
  },

对应到上面代码就是这段,返回的p2,作为result传入了parse,再通过instanceof来判断是否是由myPromise创建的,就是判断是不是一个Promise。
之后直接调用了p2.then(),所以下一个then相当于是p2.then().then()这种形式,第一个then发生值传递,直接给第二个then,且p2中是使用reject方法,所以是走onRejected()方法输出

你可能感兴趣的:(手写Promise笔记(下))