从PromiseA+学习总结到自己实现一个简易的Promise

·  阅读 86

前言

术语

1.promsie 是一个有 then方法的对象或者是函数,行为遵循本规范

2.thenable 是一个有then 方法的对象或者是函数

3.vuale是 promise状态成功时的值, 也就是resolve的参数, 包括各种数据类型,也包括undefined、thenable、或者是promise

4.reason是promise状态失败时的值,也就是reject的参数,表示拒绝的原因

5.exception 是一个使用throw抛出的异常的值

Promise的状态

1.pending

  • 初始的状态, 可以改变
  • 一个promise 在resolve 或者reject前都处于这个状态
  • 可以通过 resolve -> fulfilled状态
  • 可以通过reject -> rejected状

2.fulfilled

  • 最终态,可以改变
  • 一个promise被resolve 后变成这个状态
  • 必须要拥有一个value值

3.rejected

  • 最终太,不可以改变
  • 一个promsie被rejected后会变成这个状态
  • 必须要拥有一个reason值

then

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

promise.then(onFulfilled, onRejected)

1.参数要求
  • onFulfilled 必须是函数类型,如果不是函数类型,应该被忽略
  • onRejected 必须是函数类型,如果不是函数,应该被忽略

2.onFulfilled 特性

  • 在promsie变成fulfilled时,应该调用 onFulfilled,参数是value
  • 在promise变成 fulfilled之前,不应该被调用
  • 只能被调用一次

3.nRejected 特性

  • 在promise变成 rejected 时,应该调用 onRejected, 参数是reason
  • 在promise变成 rejected 之前, 不应该被调用.
  • 只能被调用一次

4.onFulfilled 和 onRejected 应该是微任务

  • 这里用queueMicrotask来实现微任务的调用

queueMicrotask()在mdn查看;

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

  • promise状态变成 fulfilled 后,所有的 onFulfilled 回调都需要按照then的顺序执行, 也就是按照注册顺序执行
  • promise状态变成 rejected 后,所有的 onRejected 回调都需要按照then的顺序执行, 也就是按照注册顺序执行

6.返回值

then 应该返回一个promise

promise2 = promise1.then(onFulfilled, onRejected);

  • onFulfilled 或 onRejected 执行的结果为x, 调用 resolvePromise
  • 如果 onFulfilled 或者 onRejected 执行时抛出异常e, promise2需要被reject
  • 如果 onFulfilled 不是一个函数, promise2 以promise1的value 触发fulfilled
  • 如果 onRejected 不是一个函数, promise2 以promise1的reason 触发rejected

7.Promise解析的过程

resolvePromise(promise2, x, resolve, reject)

  1. 如果promise2 和x相等的时候,那么就要返回出 reject TypeError作为原因将promise拒绝
  2. 如果 x是一个promise的话
  • 如果x是pending状态,那么promise必须保持pending状态,直到x被解决或拒绝
  • 如果x是fulfilled状态,那么要用相同的值解决promise
  • 如果x是rejected状态,用相同的原因拒绝promise

3.如果 x 是一个 object 或者 是一个 function

  • let then = x.then.
  • 如果检索属性x.then导致抛出了一个异常e,用e作为原因拒绝promise
  • 如果 then 是一个函数,用x作为this调用它。then方法的参数为俩个回调函数,第一个参数叫做resolvePromise,第二个参数叫做rejectPromise
    • resolvePromise用一个值调用 y, 则执行 resolvePromise(promise2, y, resolve, reject);

    • rejectPromise 用一个值调用 r, 用r拒绝promise

    • 如果 resolvePromise 和 rejectPromise 都调用了,那么第一个调用优先,后面的调用忽略。

    • 如果调用then则抛出异常e

    • 如果 resolvePromise 或 rejectPromise 已经被调用,则用e作为原因拒绝promise

  • 如果x不是一个对象或函数,则 resolve(x)

一步步实现一个简易第Pormise

第一步:首先定义个MyPromise的class类

class MyPromise() {
    constructor() {
        
    }
}
复制代码

第二步: 然后定义promise的三种类型状态

const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
复制代码

第三步: 然后开始设置初始值的状态

class MyPromise() {
    constructor() {
        this.status = PENDING;
        this.value = null;
        this.reason = null;
    }
} 
复制代码

第四步: 定义resolve方法 和reject方法

1.2个方法是要更改status的,从pendin改到fulfilled/rejected

2.两个函数的入参分别为value 和reason

class MyPromise() {
    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;
        }
    }
} 
复制代码

第五步:实现then方法

1.then方法接收2个参数,onFufilled 和 onRejected

 then(onFufilled,onRejected) {
 
 }
复制代码

2.检查并处理参数,判断如果不是方法,就忽略,(原样返回value和reason),定一个isFunction方法

isFunction(param) {
    return typeof param === 'function';
}
then(onFufilled,onRejected) {
     const fufilled_fn = this.isFunction(onFulfilled) ? onFufilled : (value) => {
         return value;
     }
     
     const rejected_fn = this.isFunction(onRejected) ? onRejected : (reason) => {
        throw reason;
    }
}
 
复制代码

3.根据promise的status,调用不同的方法

isFunction(param) {
    return typeof param === 'function';
}
then(onFufilled,onRejected) {
     const fufilled_fn = this.isFunction(onFulfilled) ? onFufilled : (value) => {
         return value;
     }
     
     const rejected_fn = this.isFunction(onRejected) ? onRejected : (reason) => {
        throw reason;
    }
    
     switch(this.status) {
         case FULFILLED: {
             this.fufilled_fn(this.value);
             break;
         }
         case REJECTED: {
             this.rejected_fn(this.reason);
         }
     }
}
 
复制代码

4.如果then方方法在被调用的瞬间就会执行,那么这个时候status状态还没变成fulfilled和rejected,很有可能status还在处于pending状态,

  • 那么就要首先拿到了所有的回调之后,然后才能在某个时候去执行他,
  • 这个时候就要新建2个新的数组来存储成功和失败的回调,调用then的时候,如果还是pending状态就分别存入这2个数组
class MyPromise() {
    FULFILLED_LIST = [];
    REJECTED_LIST = [];
    constructor() {
        this.status = PENDING;
        this.value = null;
        this.reason = null;
    }
    then(onFufilled,onRejected) {
         const fufilled_fn = this.isFunction(onFulfilled) ? onFufilled : (value) => {
             return value;
         }

         const rejected_fn = this.isFunction(onRejected) ? onRejected : (reason) => {
            throw reason;
        }

         switch(this.status) {
             case FULFILLED: {
                 this.fufilled_fn(this.value);
                 break;
             }
             case REJECTED: {
                 this.rejected_fn(this.reason);
                 break;
             }
             case PENDING: {
                 this.FULFILLED_LIST.push(fufilled_fn);
                 this.REJECTED_LIST.push(rejected_fn);
                 break;
             }
         }
    }
    
}
复制代码
4.2 在status发生变化的时候,就执行所有的回调,用es6的getter和setter
class MyPromise() {
    FULFILLED_LIST = [];
    REJECTED_LIST = [];
    _status = PENDING;
    constructor() {
        this.status = PENDING;
        this.value = null;
        this.reason = null;
    }
    get status() {
        this._status;
    }
    set status(newStatus) {
        this._status = newStatus;
        switch() {
            case FULFILLED:{
                this.FULFULLED_LIST.forEach(callback => {
                    callback(this.value);
                });
                break;
            }
            case REJECTED:{
                 this.REJECTED_LIST.forEach(callback => {
                     callback(this.reason);
                 });
                 break;
            }
        }
    }
}
复制代码

第六步.then的返回值

  1. 如果onFulfilled 或者 onRejected抛出了一个异常e,则promise 必须拒绝执行,并且返回e.
  then(onFufilled,onRejected) {
         const fulFilled_fn = this.isFunction(onFulfilled) ? onFufilled : (value) => {
             return value;
         }

         const rejected_fn = this.isFunction(onRejected) ? onRejected : (reason) => {
            throw reason;
        }
         const fufilledFnCatch = (resolve,reject) => {
             try {
                 fulFilled_fn(this.value);
             } catch (e){
                 reject(e);
             }
         }
         const rejectedFnCatch = (resolve,reject) => {
             try {
                 rejected_fn(this.reason);
             } catch (e){
                reject(e);
             }
         }
         switch(this.status) {
             case FULFILLED: {
                 retuen new MyPromise(fufilledFnCatch);
             }
             case REJECTED: {
                 retuen new MyPromise(rejectedFnCatch);
             }
             case PENDING: {
                 return new MyPromise((resovle,reject) => {
                      this.FULFILLED_LIST.push(fufilledFnCatch(resolve,reject));
                      this.REJECTED_LIST.push(rejectedFnCatch(resolve,reject));
                 });
             }
         }
    }
复制代码
  1. 如果onFulfilled 不是一个方法且promise1成功执行,promise必须成功执行并返回相同的值
  
const fuilledFnCatch = (resolve, reject, newPromise) => {
    try {
        if (!this.isFunction(onFulfilled)) {
            resolve(this.value);
        }
    } catch (e) {
        reject(e)
    }

};
复制代码
  1. 如果 onRejected 不是方法且 promise1拒绝执行, 那么promise2必须拒绝执行并返回相同的值
const rejectedFnCatch = (resolve, reject) => {
    try{
        if (!this.isFunction(onRejected)) {
            reject(this.reason);
        }
    } catch (e) {
        reject(e);
    }

}
复制代码

4.如果 onFulfilled 或 onRejected不是方法,那么promise2必须拒绝执行并返回相同的值,否则返回一个值x,这运行Promise解决程序(resovlePromise方法),请查看规范第7点;

       const fulFilledFnCatch = (resolve, reject, newPromise) => {
            try {
                if (!this.isFunction(onFulfilled)) {
                    resolve(this.value);
                } else {
                    const x = fulFilled_fn(this.value);
                    this.resolvePromise(newPromise, x, resolve, reject);
                }
            } catch (e) {
                reject(e)
            }
        };

        const rejectedFnCatch = (resolve, reject, newPromise) => {
            try {
                if (!this.isFunction(onRejected)) {
                    reject(this.reason);
                } else {
                    const x = rejected_fn(this.reason);
                    this.resolvePromise(newPromise, x, resolve, reject);
                }
            } catch (e) {
                reject(e);
            }
        }

        switch (this.status) {
            case FULFILLED: {
                const newPromise = new MPromise((resolve, reject) => fulFilledFnCatch(resolve, reject, newPromise));
                return newPromise;
            }
            case REJECTED: {
                const newPromise = new MPromise((resolve, reject) => rejectedFnCatch(resolve, reject, newPromise));
                return newPromise;
            }
            case PENDING: {
                const newPromise = new MPromise((resolve, reject) => {
                    this.FULFILLED_LIST.push(() => fulFilledFnCatch(resolve, reject, newPromise));
                    this.REJECTED_LIST.push(() => rejectedFnCatch(resolve, reject, newPromise));
                });
                return newPromise;
            }
        }
复制代码

第七步.实现刚刚调用过的resolvePromise方法

 resolvePromise(newPromise,x,resolve,reject) {
     // 如果newPromise 和x同时指向同一对象,那么就要以返回一个以TypeError 的错误
      if(newPromise === x) {
          return reject(new TypeError('xxxxxxx'));
      }
      if(x instanceof MyPromise) {
          // 如果x 为Promise ,则使 newPromise 接受x的状态
          x.then((y) => {
              this.resolvePromise(newPromise,y,resolve, reject);
          });
      } else if(typeof x === 'object'|| this.isFunction(x)) {
          // 如果x 为对象或者函数
          if(x === null) {
              return resolve(x);
          }
          
          let then = null;
          
          try{
              // 把x.then 赋值给 then
              then = x.then;
          } catch(error) {
                // 如果取x.then的值时候抛出错误e,以e为原因拒绝执行promsie
              return reject(error);
          }
          
          //如果then是函数
          if(this.isFunction(then)) {
              let called = false;
              // 将x作为函数的作用域 this调用
              // 传递2个回调函数作为参数,第一个参数叫做resolvePromise ,第二个参数叫做rejectPromise
              
              try{
                  this.call(x, 
                  // 如果resolvePromise 以值为参数被调用,这运resolvePromise
                  (y) => {
                  // 如果resovlePromise 和rejectPromise
                  // 或者被同一参数调用了多次,则优先采用首次调用并忽略剩下的调用
                  //实现这条需要前面假一个变量called 
                      if(called) {
                          return
                      }
                      called = true;
                      resolvePromise(newPromise, y, resovle, reject);
                  },
                  // 如果reslovPromise 以据因认为参数被调用,则以据因r拒绝执行promise
                  (r) => {
                      if(called) return;
                      called = true;
                      reject(r);
                  }
                  );
              } catch(error) {
              // 如果调用then方法抛出了异常e
              // 如果 resolvePromise 或rejectPromise已经被调用,则忽略
                  if(called) return;
                  rejected(error);
                  
              }
          } else {
              // 如果then不是方法,这以x为参数执行promise
              resolve(x);
          }
          
          
      } else {
      // 如果x不为对象或者方法,以x为参数执行promise
          resolve(x);
      }
 
 }
复制代码

第八步.onFulfilled 和 onRejected是微任务,可以用queueMicrotask()方法包裹执行函数

const fulFilledFnCatch = (resolve, reject, newPromise) => {
    queueMicrotask(() => {
        try {
           if (!this.isFunction(onFulfilled)) {
                 resolve(this.value);
           } else {
                 const x = fulFilled_fn(this.value);
                 this.resolvePromise(newPromise, x, resolve, reject);
                }
            } catch (e) {
                reject(e)
            }
        });
      
};

 const rejectedFnCatch = (resolve, reject, newPromise) => {
        queueMicrotask(() => {
            try {
                if (!this.isFunction(onRejected)) {
                    reject(this.reason);
                } else {
                    const x = rejected_fn(this.reason);
                    this.resolvePromise(newPromise, x, resolve, reject);
                }
            } catch (e) {
                reject(e);
            }
        });
            
 }
复制代码

第九步:catach方法

catch (onRejected) {
        return this.then(null, onRejected);
}
复制代码

第十步:promise.resovle

  • 将现有对象转为Promise对象,如果 Promise.resolve 方法的参数,不是具有 then 方法的对象(又称 thenable 对象),则返回一个新的 Promise 对象,且它的状态为fulfilled。
static resolve(param) {
     if (param instanceof MyPromise) {
         return param;
     }

     return new MyPromise(function (resolve) {
         resolve(param);
     });
}
复制代码

第十一步:promise.reject

  • 返回一个新的Promise实例,该实例的状态为rejected。Promise.reject方法的参数reason,会被传递给实例的回调函数。
    static reject(reason) {
        return new MPromise((resolve, reject) => {
            reject(reason);
        });
    }
复制代码

第十二步:promise.race

  • 该方法是将多个 Promise 实例,包装成一个新的 Promise 实例。 只要p1、p2、p3之中有一个实例率先改变状态,p的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给p的回调函数。
    static race(promiseList) {
        return new MPromise((resolve, reject) => {
            const length = promiseList.length;

            if (length === 0) {
                return resolve();
            } else {
                for (let i = 0; i < length; i++) {
                    MPromise.resolve(promiseList[i]).then(
                        (value) => {
                            return resolve(value);
                        },
                        (reason) => {
                            return reject(reason);
                        });
                }
            }
        });

    }
复制代码
分类:
前端
标签:
分类:
前端
标签: