promise学习笔记

103 阅读6分钟

Promise/A+规范

promise代表一个异步操作的最终结果,和promise交互的主要方式是使用.then方法,它会注册一些回调函数,用来接收promise的最终结果或者promise无法完成的原因,promise/A+规范着重关注then方法。

术语:

  1. promise是一个具有then方法对象或者函数
  2. thenable是指一个对象或者函数具有then方法
  3. value是任意合法的js对象,包括undefined、a thenable对象或者promise
  4. exception是一个可以throw的value值;
  5. reason是指示promise失败的value值

要求:

  1. promise状态

    一个promise只能是以下三种状态之一:pending、fulfilled、rejected

    • 当状态是pending时,它可以转移成fulfilled或者rejected

    • 当状态是fulfilled时

      • 它无法再转移成其他状态
      • 有一个不变的value值
    • 当状态是rejected时

      • 它无法再转移成其他状态
      • 有一个不变的reason值
  2. then方法

    promise必须有一个then方法,可以用来获取目前后者最终的结果或者失败原因;它能接受两个参数

     promise.then(onFulfilled, onRejected)
    
    • onFulfilled和onRejected都是可选参数,非必须

      • onFulfilled 默认是function(value){return value}
      • onRejected默认是function(reason){throw reason}
    • 如果onFulfilled是一个函数,

      • onFulfilled会在promise状态为fulfilled后执行,并且value为第一个参数
      • onFulfilled不会在promise状态不为fulfilled时执行
      • onFulfilled最多执行一次
    • 如果onRejected是一个函数,

      • onRejected会在promise状态为rejected后执行,并且reason为第一个参数
      • onFulfilled不会在promise状态不为rejected时执行,也不会执行多次
      • onRejected最多执行一次
    • onFulfilled和onRejected会在本地执行堆栈执行后才会调用(异步)

    • onFulfilled和onRejected是作为函数执行(没有this关键字)

    • 同一个promise的then方法可以多次调用

      • 如果promise是fulfilled,所有的onFulfilled都会按照then方法注册顺序进行执行;
      • 如果promise是rejected,所有的onRejected都会按照then方法注册顺序进行执行;
    • then方法必须返回一个promise

       promise2 = promise1.then(onFulfilled, onRejected);
      
      • 如果onFulfilled或者onRejected返回value x,进行promise解析过程【[Resolve]】(promise2,x)
      • 如果onFulfilled或者onRejected抛出了一个异常e,则promise2会被rejected,e作为reason
      • 如果onFulfilled不是一个函数并且promise1 fulfilled,则promise2也是fulfillid状态,value值和promise1相同。
      • 如果onRejected不是一个函数并且promise1 rejected,则promise2也是rejected状态,reason值和promise1相同。
  3. promise解析过程【[Resolve]】(promise,x)

    promise的解析过程是要给抽象的操作,入参是一个promise和一个值x。如果x是要thenable的,他会试图让promise采纳x的状态和值。否则,他会设置promise状态为fulfilled,值为x。

    解析过程如下:

    • 如果promise和x指向同一个对象,则reject这个promise,reason设置为TypeError(避免then的调用栈循环)

    • 如果x是一个promise,promise将使用x的状态

      • 如果x是pending,则promise也是pending,直到x变为fulfilled或者rejected
      • 如果x是fulfilled, 则promise也用x的value进行fulfill(resolve)
      • 如果x是rejected,则promise也使用x的reason进行reject
    • 否则,如果x是一个对象或者函数

      • then赋值为x.then

      • 如果x.then抛出异常e,则reject promise,原因reason值为e

      • 如果then是一个函数,执行下面

         then(resolvePromise,rejectPromise)
        
        • 如果resolvePromise执行了,值为y,则进行解析过程【[Resolve]】(promise,y)

        • 如果rejectPromise执行了,reason为r,则promise状态设为rejected,reson设为r。

        • 如果resolvePromise和rejectPromise都被调用了,或者使用相同的参数调用了多次,则只有第一次的调用生效,后面的调用都将被忽略。

        • 如果then方法的调用抛出了异常e,

          • 如果resolvePromise或者rejectPromise被调用了,则忽略e
          • 否则,promise将被reject,e作为reason值。
        • 如果then不是一个函数,则promise 进行fulfill,值为x

    • 如果x不是一个对象或者函数,fulfill 这个promise,值为x

    异步编程

promise可以支持链式调用,解决回调地狱的问题

 asyncFunc1({
         xxx;
     asyncFunc2({
         asyncFunc3({
             xxx;
         })
         xxx;
     })
 })

使用promise可以封装异步操作,异步逻辑和回调处理可以分开编写

 const p = new Promise((resolve,reject)=>{
     if(status){
         resolve(val);
     }else{
         reject(err);
     }
 })
 p.then((val)=>{
     //resolve callback
     sucFunc1(val);
 },(err)=>{
     //reject callback
     errFunc2(err);
 })
 function sendAjax(url) {
   return new Promise((resolve, reject) => {
     let xhr = new XMLHttpRequest();
     xhr.open("GET", url);
     xhr.send();
     xhr.onreadystatechange = function () {
       if (xhr.readyState === 4) {
         if (xhr.status >= 200 && xhr.status < 300) {
           resolve(xhr.response);
         } else {
           reject(xhr.status);
         }
       }
     };
   });
 }
  sendAjax("https://www.baidu.com").then((data) => console.log(data));

Promise的状态

promise实例对象有两个属性:PromiseState,PromiseResult。

  • 【PromiseState】
  1. pending 初始状态
  2. fullfilled 成功
  3. rejected 失败
  • [PromiseResult]

成功时,值为resovle的value;

失败时,值为reject的value;

非promise的对象,值为undefined;

  • 改变PromiseState状态的方式:

resolve:pending-->fullfilled;

reject/throw: pending-->rejected

PromiseState的值一旦改变就不会再发生变化;

Promise的API

  • 构造函数
 const promise = new Promise((resolve,reject)=>{xxx})
  • promise.then.catch代码结构

    异常穿透 最后的catch可以捕获前面的所有promise和then中出现的异常和reject的结果

  • Promise.resolve()

  • Promise.reject()
  • Promise.all([promise1,promise2,....])

promise数组都成功才成功,成功结果为所有promise的结果数组;

有一个promise失败,则promise.all返回失败的promise,结果为失败的promise值

  • Promise.race([promise1,promise2,....])

由最先返回的promise决定最终promise状态和结果

  • 中断promise链

可以在then中创建一个pending状态的promise。

 const p =new Promise((resolve,reject)=>{
     resolve();
 })
 p.then({
     //中断
     return new Promise(()=>{})
 }).then(xxx).then(xxx)

手写promise

image-20220412110419899.png

  • 构造函数

    浏览器F12查看Promise的构造函数

image-20220412110816165-16497329001471.png

构造函数执行器excurtor写明promise的同步或者异步处理逻辑,Promise中的核心resolve和reject函数方法,用于改变promise的状态和值,对异步逻辑进行回调触发。
 function Promise(excutor) {
   //状态
   this.PromiseStatus = "pending";
   //promise结果
   this.PromiseResult = undefined;
   //异步执行结果回调函数定义,采用数组的形式可以支持绑定多个回调函数
   this.callback = [];
   //常用写法,解决this指向问题
   const that = this;
   //resolve函数
   function resolve(val) {
     //判断状态,保证promise状态只能改变一次
     if (that.PromiseStatus !== "pending") return;
     //改变promiseStatus对象状态,
     that.PromiseStatus = "fullfilled";
     //设置promiseResult值
     that.PromiseResult = val;
     //调用成功的回调函数
     that.callback.forEach((item) => {
       item.onResolved(val);
     });
   }
   //reject函数
   function reject(err) {
     //判断状态,保证promise状态只能改变一次
     if (that.PromiseStatus !== "pending") return;
     //改变promiseStatus对象状态
     that.PromiseStatus = "rejected";
     //设置promiseResult值
     that.PromiseResult = err;
     //调用成功的回调函数
     that.callback.forEach((item) => {
       item.onRejected(err);
     });
   }
   //同步调用
   try {
     excutor(resolve, reject);
   } catch (error) {
     reject(error);
   }
 }
  • then API

    then 写回调逻辑,定义promise状态改变后需要执行的操作,返回值也是一个promise

 Promise.prototype.then = function (onResolved, onRejected) {
   //this指向问题
   const self = this;
   //实现异常穿透,增加默认的onRejected回调函数
   if (typeof onRejected !== "function") {
     onRejected = (reason) => {
       throw reason;
     };
   }
   if (typeof onResolved !== "function") {
     onResolved = (value) => {
       return value;
     };
   }
   //then返回的是一个promise,支持链式调用
   return new Promise((resolve, reject) => {
   
     //定义处理函数,type会回调函数类型
     function callback(type) {
       try {
         let result = type(self.PromiseResult);
         //如果result是一个promise,则该promise的状态和结果为返回的结果
         if (result instanceof Promise) {
           result.then(
             (v) => {
               resolve(v);
             },
             (r) => {
               reject(r);
             }
           );
         } else {
           //返回的promise对象状态为成功,值为result,result可能会undifined
           resolve(result);
         }
       } catch (err) {
          reject(err);
       }
     }
     //promiseStatus为fullfilled或者rejected表明在then函数定义时,promise执行结果已经执行完   成,可以直接触发回调函数
     if (this.PromiseStatus === "fullfilled") {
       callback(onResolved);
     }
     if (this.PromiseStatus === "rejected") {
       callback(onRejected);
     }
     //对于异步操作,then定义时,promiseStatus并没有发生改变,此时做的事情是将回调函数保存promise对象中去,等待异步操作执行resolve或者reject方法是触发回调函数执行;
     if (this.PromiseStatus === "pending") {
       //保存回调函数
       this.callback.push({
         onResolved: function () {
           callback(onResolved);
         },
         onRejected: function () {
           callback(onRejected);
         },
       });
     }
   });
 };
  • catch API

catch可以利用then方法的第二个回调函数实现,resolve回调设置成undefined

 Promise.prototype.catch = function (onRejected) {
   return this.then(undefined, onRejected);
 };

\