笔记-Promise

135 阅读7分钟

PromiseA+规范

  1. promise 是一个有then方法的对象或者是函数
  2. thenable 是一个有then方法的对象或者是函数
  3. value 是promise状态成功时的值,也就是resolve的参数, 包括各种数据类型, 也包括undefined/thenable或者是 promise
  4. reason 是promise状态失败时的值, 也就是reject的参数, 表示拒绝的原因
  5. exception 是一个使用throw抛出的异常值

Promise States

promise应该有三种状态. 要注意他们之间的流转关系.

  1. pending

    1.1 初始的状态, 可改变. 1.2 一个promise在resolve或者reject前都处于这个状态。

    1.3 可以通过 resolve -> fulfilled 状态;

    1.4 可以通过 reject -> rejected 状态;

  2. fulfilled

    2.1 最终态, 不可变.

    2.2 一个promise被resolve后会变成这个状态.

    2.3 必须拥有一个value值

  3. rejected

    3.1 最终态, 不可变. 3.2 一个promise被reject后会变成这个状态 3.3 必须拥有一个reason

Tips: promise的状态流转

pending -> resolve(value) -> fulfilled

pending -> reject(reason) -> rejected

then

promise应该提供一个then方法, 用来访问最终的结果, 无论是value还是reason.

promise.then(onFulfilled, onRejected)
  1. 参数要求

    1.1 onFulfilled 必须是函数类型, 如果不是函数, 应该被忽略.

    1.2 onRejected 必须是函数类型, 如果不是函数, 应该被忽略.

  2. onFulfilled 特性

    2.1 在promise变成 fulfilled 时,应该调用 onFulfilled, 参数是value

    2.2 在promise变成 fulfilled 之前, 不应该被调用.

    2.3 只能被调用一次(所以在实现的时候需要一个变量来限制执行次数)

  3. onRejected 特性

    3.1 在promise变成 rejected 时,应该调用 onRejected, 参数是reason

    3.2 在promise变成 rejected 之前, 不应该被调用.

    3.3 只能被调用一次(所以在实现的时候需要一个变量来限制执行次数)

  4. onFulfilled 和 onRejected 应该是微任务

    使用queueMicrotask来实现微任务的调用.

  5. then方法可以被调用多次

    5.1 promise状态变成 fulfilled 后,所有的 onFulfilled 回调都需要按照then的顺序执行, 也就是按照注册顺序执行(所以在实现的时候需要一个数组来存放多个onFulfilled的回调)

    5.2 promise状态变成 rejected 后,所有的 onRejected 回调都需要按照then的顺序执行, 也就是按照注册顺序执行(所以在实现的时候需要一个数组来存放多个onRejected的回调)

  6. 返回值

    then 应该返回一个promise

    promise2 = promise1.then(onFulfilled, onRejected);
    

    6.1 onFulfilled 或 onRejected 执行的结果为x, 调用 resolvePromise( 这里大家可能难以理解, 可以先保留疑问, 下面详细讲一下resolvePromise是什么东西 )

    6.2 如果 onFulfilled 或者 onRejected 执行时抛出异常e, promise2需要被reject

    6.3 如果 onFulfilled 不是一个函数, promise2 以promise1的value 触发fulfilled

    6.4 如果 onRejected 不是一个函数, promise2 以promise1的reason 触发rejectet

  7. resolvePromise

    resolvePromise(promise2, x, resolve, reject)
    

    7.1 如果 promise2 和 x 相等,那么 reject TypeError

    7.2 如果 x 是一个 promsie

         如果x是pending态,那么promise必须要在pending,直到 x 变成 fulfilled or rejected.
         如果 x 被 fulfilled, fulfill promise with the same value.
         如果 x 被 rejected, reject promise with the same reason.
         
    

    7.3 如果 x 是一个 object 或者 是一个 function

     let then = x.then.
     如果 x.then 这步出错,那么 reject promise with e as the reason.
     如果 then 是一个函数,then.call(x, resolvePromiseFn, rejectPromise)
         resolvePromiseFn 的 入参是 y, 执行 resolvePromise(promise2, y, resolve, reject);
         rejectPromise 的 入参是 r, reject promise with r.
         如果 resolvePromise 和 rejectPromise 都调用了,那么第一个调用优先,后面的调用忽略。
         如果调用then抛出异常e 
             如果 resolvePromise 或 rejectPromise 已经被调用,那么忽略
             则,reject promise with e as the reason
     如果 then 不是一个function. fulfill promise with x.
    

实现一个 promise

  1. 定义 Mpromise 类 及 三种状态

        const PENDING = 'pending';
        const FULFILLED = 'fulfilled';
        const REJECTED = 'rejected';
        class Mpromise {
            constructor()
        }
    
  2. 设置初始状态

    class Mpromise {
      constructor() {
        this.status = PENDING;
        this.value = null;
        this.reason = null;
      }
    }
    
  3. resolve 和 reject 方法

    class Mpromise {
      constructor() {
        this.status = PENDING;
        this.value = null;
        this.reason = null;
      }
    
      resolve(value) {
        if (this.status === PENDING) {
          this.value = value;
          this.status = FULFILLED;
        }
      }
    
      reject(reason) {
        if (this.status === PENDING) {
          this.reason = reason;
          this.status = REJECTED;
        }
      }
    }
    
  4. promise 形参

    new Promise((resolve, reject) => {});
    
    • 接收参数是一个函数,函数接收 resolve 和 reject 两个参数
    • new Promise 的时候就要执行这个函数 ,如果执行出现任何报错,都要 reject 出去
    class Mpromise {
      constructor() {
        this.status = PENDING;
        this.value = null;
        this.reason = null;
    
        try {
          fn(this.resolve.bind(this), this.reject.bind(this));
        } catch (error) {
          this.reject(error);
        }
      }
    }
    
  5. then 方法

    then(onFulfilled, onRejected);
    
    1. then 接收两个参数 onFulfilled 和 onRejected

    2. 处理参数,如果不是函数,包装成函数远洋返回 value 或者 reason

      isFunction(param) {
        return typeof param === 'function';
      }
      then(onFulfilled,onRejected){
        const realOnFufilled = this.isFunction(onFulfilled)?onFulfilled:(value)=>{
          return value;
        }
        const realOnRejected = this.isFunction(onRejected)?onRejected:(reason)=>{
          throw reason;
        }
      }
      
    3. then 方法整体返回一个新的 promise

        then(onFulfilled,onRejected){
        const realOnFufilled = this.isFunction(onFulfilled)?onFulfilled:(value)=>{
          return value;
        }
        const realOnRejected = this.isFunction(onRejected)?onRejected:(reason)=>{
          throw reason;
        }
        const promise2 = new MPromise((resolve,reject)=>{});
        return promise2;
      }
      
    4. 根据当前 promise 的状态 调用不同的函数

        then(onFulfilled,onRejected){
        const realOnFufilled = this.isFunction(onFulfilled)?onFulfilled:(value)=>{
          return value;
        }
        const realOnRejected = this.isFunction(onRejected)?onRejected:(reason)=>{
          throw reason;
        }
        const promise2 = new MPromise((resolve,reject)=>{
          switch(this.status){
            case FULFILLED:{
              realOnFufilled(this.value);
              break;
            }
            case REJECTED:{
              realOnRejected(this.reason);
              break;
            }
          }
        });
        return promise2;
      }
      
    5. 如果是异步,then 方法执行的时候可能还是 pending 状态,这时候就执行不到回调,所以我们需要监听 status ,当状态变为 fulfilled 或者 rejected 时,去执行 callback

      1. then 执行的时候如果是 pending ,则将 callback 存用数组起来,状态改变时 按顺序执行

          FULFILLED_CALLBACK_LIST = [];
          REJECTED_CALLBACK_LIST = [];
          then(onFulfilled,onRejected){
          const realOnFufilled = this.isFunction(onFulfilled)?onFulfilled:(value)=>{
            return value;
          }
          const realOnRejected = this.isFunction(onRejected)?onRejected:(reason)=>{
            throw reason;
          }
          const promise2 = new MPromise((resolve,reject)=>{
            switch(this.status){
              case FULFILLED:{
                realOnFufilled(this.value);
                break;
              }
              case REJECTED:{
                realOnRejected(this.reason);
                break;
              }
              case PENDING:{
                FULFILLED_CALLBACK_LIST.push(realOnFufilled);
                REJECTED_CALLBACK_LIST.push(realOnRejected);
              }
            }
          });
          return promise2;
        }
        
      2. 在 status 发生改变的时候去执行回调,这里使用 es6 的 getter 和 setter 监听

        _status = PENDING;
        
        get status(){
          return this._status;
        }
        set status(newStatus){
          switch (newStatus){
            case FULFILLED:{
              this.FULFILLED_CALLBACK_LIST.forEach(callback=>{
                callback(this.value);
              })
            }
            case REJECTED:{
              this.REJECTED_CALLBACK_LIST.forEach(callback=>{
                callback(this.reason);
              })
            }
          }
        }
        
  6. then 的返回值

    then 的返回值是一个 Promise, 那么接下来具体讲一下返回 promise 的 value 和 reason 是什么.

    1. 如果 onFulfilled 或 onRejected 抛出异常 error ,则promise2必须拒绝执行并返回原因(手动catch,报错就reject)

      then(onFulfilled,onRejected){
          const realOnFufilled = this.isFunction(onFulfilled)?onFulfilled:(value)=>{
              return value;
          }
          const realOnRejected = this.isFunction(onRejected)?onRejected:(reason)=>{
              throw reason;
          }
          const promise2 = new MPromise((resolve,reject)=>{
              const fulfilledMicrotask = ()=>{
                  try{
                      realOnFufilled(this.value);
                  }catch(error){
                      reject(error);
                  }
              }
              const rejectedMicrotask = ()=>{
                  try{
                      realOnRejected(this.reason);
                  }catch(error){
                      reject(error);
                  }
              }
              switch(this.status){
              case FULFILLED:{
                  fulfilledMicrotask();
                  break;
              }
              case REJECTED:{
                  rejectedMicrotask();
                  break;
              }
              case PENDING:{
                  FULFILLED_CALLBACK_LIST.push(fulfilledMicrotask);
                  REJECTED_CALLBACK_LIST.push(rejectedMicrotask);
              }
              }
          });
              return promise2;
          }
      
    2. 如果 onFulfilled 不是函数且 promise1 成功执行, promise2 必须成功执行并返回相同的值

    3. 如果 onRejected 不是函数且 promise1 拒绝执行, promise2 必须拒绝执行并返回相同的据因。

    需要注意的是,如果promise1的onRejected执行成功了,promise2应该被resolve

      const realOnFulfilled = this.isFunction(onFufilled)?onFufilled:(value)=>{
          return value;
      }
    
      const realOnRejected = this.isFunction(onRejected)?onRejected:(reason)=>{
          throw reason;
      }
    
    1. 如果 onFufilled 或者 onRejected 返回一个值 x ,则执行resolvePromise()
       then(onFulfilled,onRejected){
           const realOnFufilled = this.isFunction(onFulfilled)?onFulfilled:(value)=>{
               return value;
           }
           const realOnRejected = this.isFunction(onRejected)?onRejected:(reason)=>{
               throw reason;
           }
           const promise2 = new MPromise((resolve,reject)=>{
               const fulfilledMicrotask = ()=>{
                   try{
                       const x = realOnFufilled(this.value);
                       this.resolvePromise(promise2,x,resolve,reject);
                   }catch(error){
                       reject(error);
                   }
               }
               const rejectedMicrotask = ()=>{
                   try{
                       const x = realOnRejected(this.reason);
                       this.resolvePromise(promise2,x,resolve,reject);
                   }catch(error){
                       reject(error);
                   }
               }
               switch(this.status){
               case FULFILLED:{
                   fulfilledMicrotask();
                   break;
               }
               case REJECTED:{
                   rejectedMicrotask();
                   break;
               }
               case PENDING:{
                   FULFILLED_CALLBACK_LIST.push(fulfilledMicrotask);
                   REJECTED_CALLBACK_LIST.push(rejectedMicrotask);
               }
               }
           });
               return promise2;
           }
      
  7. resolvePromise 方法

    resolvePromise(promise2,x,resolve,reject){
        // 如果传入的新promise 和 x指向同一个对象,以TypeError拒绝执行新的promise,避免死循环
        if(promise2 === x){
            return reject(new TypeError('promise和返回值不能相等'))
        }
    
        // x 如果是一个promise,则使 newPromise 接受 x 的状态
        // 也就是继续执行x,如果执行的时候拿到一个y,还要继续解析y
        if(x instansof MPromise){
            queueMicrotask(()=>{
                x.then((y)=>{
                    this.resolvePromise(promise2,y,resolve,reject);
                },reject)
            })
    
        }else if(typeof x === 'object' || this.isFunction(x)){
            // 如果 x 为对象或者函数
            if(x === null){
                // null也会被判为对象
                return resolve(x);
            }else{
    
                let then = null;
                try{
                    //防止x.then报错
                    then = x.then;
    
                }catch(error){
                    return reject(error)
                }
    
                if(isFunction(then)){
                    try{
                        then.call(
                            x,
                            (y)=>{
                                this.resolvePromise(promise2,y,resolve,reject);
                            },
                            (r)=>{
                                reject(r)
                            }
                        )
                    }catch(error){
                        reject(error)
                    }
    
                }else{
                    // then不是函数,以 x 为参数执行 promise
                    resolve(x);
                }
            }
        }else{
            // 如果 x 不为对象或者函数,以 x 为参数执行 promise
            resolve(x);
        }
    
    }
    
  8. 其他方法

    1. race 接收一个存放promise的数组 返回最先执行完成的那个promise的结果
    MPromise.race = function(promiseList){
        return new MPromise((resolve, reject) => {
            const length = promiseList.length;
            if (length === 0) {
                resolve();
            } else {
                for (let i = 0; i < promiseList.length; i++) {
                    MPromise.resolve(promiseList[i])
                        .then(value => {
                            return resolve(value);
                        })
                        .catch(reason => {
                            return reject(reason);
                        });
                }
            }
        });
    }
    
    1. all方法 接收一个存放promise的数组 按顺序(数组)返回所有promise的结果 如果某个promise被 reject 则整个结果为reject
    MPromise.all = function(promiseList){
        return new MPromise((resolve, reject) => {
            let valueList = [];
            let count = 0;
            for (let i = 0; i < promiseList.length; i++) {
                MPromise.resolve(promiseList[i])
                    .then(value => {
                        // 不能使用push 保证顺序
                        valueList[i] = value;
                        // if(valueList.length === length){ 这么写会出现 索引1先赋值,索引0未赋值,这时数组长度已经是2
                        //   return resolve(valueList);
                        // }
    
                        // 正确做法 定义一个计数器
                        count++;
                        if (count === promiseList.length) {
                            resolve(valueList);
                        }
                    })
                    .catch(reason => {
                        reject(reason);
                    });
            }
        });
    }
    
    1. finally 方法 接收一个回调 不管promise是resolve还是reject 都去执行回调
    MPromise.prototype.finally = function(callback){
        return this.then(
            value=>{
                return MPromise.resolve(callback()).then(()=>value);
            },
            err=>{
                return MPromise.resolve(callback()).then(()=>{throw err});
            }
        )
    }