美文网首页
Promise是什么,如何手写一个符合 PromiseA+规范的

Promise是什么,如何手写一个符合 PromiseA+规范的

作者: WebsnowDrop | 来源:发表于2024-08-04 11:09 被阅读0次

    什么是 Promise

    参考 MDN 定义Promise

    cosnt p = new Promise((resolve,reject)=>{})
    

    一个 Promise 必然处于以下几种状态之一:
    peding:初始状态,既没有被兑现,也没有被拒绝。
    fulfilled:意味着操作成功完成。
    rejected:意味着操作失败。

    为什么使用Promise

    假设有一下代码,实现每过一秒钟输出一句话

    function fn1(callback) {
      setTimeout(()=>{
        console.log('fn1')
        callback()
      }, 1000)
    }
    function fn2(callback) {
      setTimeout(()=>{
        console.log('fn2')
        callback()
      }, 1000)
    }
    function fn3() {
      setTimeout(()=>{
        console.log('fn3')
      }, 1000)
    }
    fn1(function(){
      fn2(function(){
        fn3()
      })
    })
    

    上面 fn1 里调用fn2,fn2 里调用 fn3 这种就形成了回调地狱,而使用 Promise可以让代码变得更优雅。下面用 Promise 改造

    function fn1(){
      return new Promise((resolve,reject)=>{
        setTeimeout(()=>{
          resolve('fn1')
        },1000)
      })
    }
    function fn2(){
      return new Promise((resolve,reject)=>{
        setTeimeout(()=>{
          resolve('fn2')
        },1000)
      })
    }
    function fn3(){
      return new Promise((resolve,reject)=>{
        setTeimeout(()=>{
          resolve('fn3')
        },1000)
      })
    }
    fn1()
      .then(fn2)
      .then(fn3)
    

    如何手写一个 Promise

    参考Promises/A+规范

    我们先考虑如何使用Promise
    可以new 一个promise创建一个实例,接收一个函数作为参数,这个函数有两个参数分别是resolve,reject

    const p = new Promise((resolve, reject) => {
        //成功回调
        resolve(data)
        //失败回调
        reject(reason)
    });
    

    有 then 方法,支持链式调用

    p.then(console.log('f1'),console.error('f2'))
     .then(console.log('f3'),console.error('f4'))
    

    下面开始手写一个promise

    constructor

    我们知道new 一个promise实例时,参数fn数是是同步执行的

    class MyPromise {
      constructor(fn) {
        const resolve = (data) => {};
        const reject = (reason) => {};
        fn.call(undefined, resolve, reject);
      }
      then(onFulfilled, onRejected) {}
    }
    console.log(1)
    const p = new MyPromise((resolve, reject) => {
      console.log("执行了");
    });
    console.log(2)
    
    image.png

    一个promise必须处于以下三种状态之一:pending(待定)、fulfilled(实现)或rejected(拒绝),处于pending状态下的promise可以转为fulfilled或者rejected状态,一但状态改变之后,状态就不可变了。这样在我们的promise中添加上状态部分的代码

    class MyPromise {
      //2.1.1
      #status = "pending";
      constructor(fn) {
        const resolve = (data) => {
          //2.1.2.1
          if (this.#status !== "pending") return;
          this.#status = "fulfilled";
        };
        const reject = (reason) => {
          //2.1.3.1
          if (this.#status !== "pending") return;
          this.#status = "rejected";
        };
        fn.call(undefined, resolve, reject);
      }
      then(onFulfilled, onRejected) {}
    }
    

    resolve和reject执行可以传递参数,


    image.png

    下面添参数部分的代码

    class MyPromise {
      //规范 2.1.1
      #status = "pending";
      #result = undefined;
      constructor(fn) {
        const resolve = (data) => {
          //规范 2.1.2.1
          if (this.#status !== "pending") return;
          this.#status = "fulfilled";
          //2.1.2.2
          this.#result = data;
        };
        const reject = (reason) => {
          //规范 2.1.3.1
          if (this.#status !== "pending") return;
          this.#status = "rejected";
          //2.1.3.2
          this.#result = reason;
        };
        fn.call(undefined, resolve, reject);
      }
      then(onFulfilled, onRejected) {}
    }
    

    还有一种情况,new promise的时候抛出一个错误时,promise状态变为rejected,结果为抛出的错误


    image.png

    所以调用fn是需要try catch处理

    class MyPromise {
      //规范 2.1.1
      #status = "pending";
      #result = undefined;
      constructor(fn) {
        const resolve = (data) => {
          //规范 2.1.2.1
          if (this.#status !== "pending") return;
          this.#status = "fulfilled";
          //2.1.2.2
          this.#result = data;
        };
        const reject = (reason) => {
          //规范 2.1.3.1
          if (this.#status !== "pending") return;
          this.#status = "rejected";
          //2.1.3.2
          this.#result = reason;
        };
        try {
          fn.call(undefined, resolve, reject);
        } catch (error) {
          reject(error)
        }
      }
      then(onFulfilled, onRejected) {}
    }
    

    then

    image.png

    then接收两个参数,onFulfilledonRejected,promise状态为fulfilled时执行onFulfilled回调,状态为rejected时执行onRejected回调,then方法支持链式调用,所以then返回的还是一个promise

    class MyPromise {
      //规范 2.1.1
      #status = "pending";
      #result = undefined;
      constructor(fn) {
        const resolve = (data) => {
          //规范 2.1.2.1
          if (this.#status !== "pending") return;
          this.#status = "fulfilled";
          //2.1.2.2
          this.#result = data;
        };
        const reject = (reason) => {
          //规范 2.1.3.1
          if (this.#status !== "pending") return;
          this.#status = "rejected";
          //2.1.3.2
          this.#result = reason;
        };
        try {
          fn.call(undefined, resolve, reject);
        } catch (error) {
          this.#result = error;
        }
      }
      then(onFulfilled, onRejected) {
        if(this.#status==='fulfilled'){
          onFulfilled(this.#result)
        }
        if(this.#status==='rejected'){
          onRejected(this.#result)
        }
        //2.2.7
        return new MyPromise((resolve, reject) => {});
      }
    }
    

    规范2.2.4 onFulfilled 和 onRejected 只有在执行环境堆栈仅包含平台代码时才可被调用,所以在执行onFulfilled和onRejected时要用异步调用

    class MyPromise {
      #status = "pending"; //规范2.1.1  初始状态为 pending
      #result = undefined; //返回结果
      //接收一个 fn 函数,
      constructor(fn) {
        const resolve = (data) => {
          //规范2.1.2  不能转换为其他任何状态
          if (this.#status !== "pending") return;
          this.#status = "fulfilled"; //规范2.1.2  状态变为 fulfilled
          this.#result = data;
        };
        //规范 2.1.3.2  有一个失败原因
        const reject = (reason) => {
          //规范2.1.3  不能转换为其他任何状态
          if (this.#status !== "pending") return;
          this.#status = "rejected"; //2.1.3    状态变为 rejected
          this.#result = reason;
        };
    
        // 如果函数执行过程中出错,状态变为rejected
        try {
          fn.call(undefined, resolve, reject);
        } catch (error) {
          this.reject(error);
        }
      }
      //2.2 有一个 then 方法,// 2.2.1 有两个可选参数
      then(onFulfilled, onRejected) {
        //2.2.1.1 如果onFulfilled不是一个函数,它必须被忽略
        //2.2.5 onFulfilled和onRejected必须作为函数被调用(即没有this值
        onFulfilled = typeof onFulfilled === "function" ? onFulfilled : () => {};
        // 2.2.1.2 如果onRejected不是一个函数,它必须被忽略
        //2.2.5 onFulfilled和onRejected必须作为函数被调用(即没有this值
        onRejected = typeof onRejected === "function" ? onRejected : () => {};
    
    
        //2.2.7 必须返回一个 promise
        cosnt p2 = new MyPromise((resolve, reject) => {
          if (this.#status === "fulfilled") {
            //2.2.4 onFulfilled或onRejected不能在执行上下文堆栈中只包含平台代码之前调用
            setTimeout(() => {
              onFulfilled(this.#result);
            });
          }
          if (this.#status === "rejected") {
            setTimeout(() => {
              onRejected(this.#result);
            });
          }
        });
      }
      return p2
    }
    //测试 输出 1 promise1 4 2
    console.log("1");
    var p = new MyPromise((resolve, reject) => {
      console.log("promise1");
      resolve(2);
    });
    p.then(
      (res) => {
        console.log(res)
      },
      () => {
        console.log("reject1");
      }
    );
    console.log("4");
    

    测试结果看似没有问题,如果代码稍微改动一下,就有问题了

    console.log("1");
    var p = new MyPromise((resolve, reject) => {
      setTimeout(()=>{
         console.log("promise1");
         resolve(2);
      })
    });
    p.then(
      (res) => {
        console.log(res)
      },
      () => {
        console.log("reject1");
      }
    );
    console.log("4");
    
    image.png
    resolve的结果不输出了,因为then方法中只对fulfilledrejected的状态做了处理,pending状态时没有处理,setTimeout中的代码是放到异步任务队列(宏任务)中处理的,运行到p.then时,promise状态始终是pending状态
    下面在then中加入pending状态的处理
    class MyPromise {
      #status = "pending"; //规范2.1.1  初始状态为 pending
      #result = undefined; //返回结果
      //接收一个 fn 函数,
      constructor(fn) {
        this.queue = [];
        this.state = "pending";
        const resolve = (data) => {
          //规范2.1.2  不能转换为其他任何状态
          if (this.state !== "pending") return;
          this.state = "fulfilled"; //规范2.1.2  状态变为 fulfilled
          this.#result = data;
        };
        //规范 2.1.3.2  有一个失败原因
        const reject = (reason) => {
          //规范2.1.3  不能转换为其他任何状态
          if (this.state !== "pending") return;
          this.state = "rejected"; //2.1.3    状态变为 rejected
          this.#result = reason;
        };
    
        // 如果函数执行过程中出错,状态变为rejected
        try {
          // this.queue.push([resolve, reject]);
          fn.call(undefined, resolve, reject);
        } catch (error) {
          reject(error);
        }
      }
      //2.2.1 有一个then方法,有两个可选参数
      then(onFulfilled, onRejected) {
        //2.2.1.1 如果onFulfilled不是一个函数,它必须被忽略
        //2.2.5 onFulfilled和onRejected必须作为函数被调用(即没有this值
        onFulfilled = typeof onFulfilled === "function" ? onFulfilled : () => {};
        // 2.2.1.2 如果onRejected不是一个函数,它必须被忽略
        //2.2.5 onFulfilled和onRejected必须作为函数被调用(即没有this值
        onRejected = typeof onRejected === "function" ? onRejected : () => {};
        //2.2.7 必须返回一个 promise
        const p2 = new MyPromise((resolve, reject) => {
          //2.2.2.2 在promise实现之前不得调用它。
          if (this.state === "fulfilled") {
            //2.2.4 onFulfilled或onRejected不能在执行上下文堆栈中只包含平台代码之前调用。
            setTimeout((data) => {
              onFulfilled(this.#result);
            });
          }
          //2.2.3.2 在promise被拒绝之前不得调用它。
          if (this.state === "rejected") {
            //2.2.2.1 它必须在promise实现后调用,并以promise的值作为其第一个参数。
            setTimeout((reason) => {
              onRejected(reason);
            });
          }
          //
          if (this.state === "pending") {
            
          }
        });
        return p2;
      }
      #resolvePromise(promise, x) {
        try {
          if (promise === x) {
          }
        } catch (error) {}
      }
    }
    

    问题来了,pending状态时要做什么呢?
    我们知道hen方法中的onFulfilledonRejected执行时机一定是等promise状态变为fulfilled或者rejected后才执行。也就是说要等到resolve或reject执行之后再执行。很简单,resolve时调用onFulfilled就行了,reject时调用onRejected,
    注意then方法支持多次调用,如何多次调用呢,很简单,将onFulfilled和onRejected放入一个队列中,resolve执行时调用所有成功的回调onFulfilled,reject执行时调用所有失败的回调onRejected

    class MyPromise {
      #status = "pending"; //规范2.1.1  初始状态为 pending
      #result = undefined; //返回结果
      //接收一个 fn 函数,
      constructor(fn) {
        this.queue = []; //添加一个队列,存储onFulfilled, onRejected
        this.state = "pending";
        const resolve = (data) => {
          console.log('data:',data)
          //规范2.1.2  不能转换为其他任何状态
          if (this.state !== "pending") return;
          this.state = "fulfilled"; //规范2.1.2  状态变为 fulfilled
          this.#result = data;
          // 执行resolve时再调用所有onFulfilled
         this.queue.map(callbacks=>{
            const task = this.queue.shift()
            task[0](data)
         })
        };
        //规范 2.1.3.2  有一个失败原因
        const reject = (reason) => {
          //规范2.1.3  不能转换为其他任何状态
          if (this.state !== "pending") return;
          this.state = "rejected"; //2.1.3    状态变为 rejected
          this.#result = reason;
          // 执行reject时再调用所有onRejected
           this.queue.map(callbacks=>{
            const task = this.queue.shift()
            task[1](reason)
         })
        };
    
        // 如果函数执行过程中出错,状态变为rejected
        try {
          // this.queue.push([resolve, reject]);
          fn.call(undefined, resolve, reject);
        } catch (error) {
          reject(error);
        }
      }
      //2.2.1 有一个then方法,有两个可选参数
      then(onFulfilled, onRejected) {
        //2.2.1.1 如果onFulfilled不是一个函数,它必须被忽略
        //2.2.5 onFulfilled和onRejected必须作为函数被调用(即没有this值
        onFulfilled = typeof onFulfilled === "function" ? onFulfilled : () => {};
        // 2.2.1.2 如果onRejected不是一个函数,它必须被忽略
        //2.2.5 onFulfilled和onRejected必须作为函数被调用(即没有this值
        onRejected = typeof onRejected === "function" ? onRejected : () => {};
        //2.2.7 必须返回一个 promise
        const p2 = new MyPromise((resolve, reject) => {
          //2.2.2.2 在promise实现之前不得调用它。
          if (this.state === "fulfilled") {
            //2.2.4 onFulfilled或onRejected不能在执行上下文堆栈中只包含平台代码之前调用。
            setTimeout((data) => {
              onFulfilled(this.#result);
            });
          }
          //2.2.3.2 在promise被拒绝之前不得调用它。
          if (this.state === "rejected") {
            //2.2.2.1 它必须在promise实现后调用,并以promise的值作为其第一个参数。
            setTimeout((reason) => {
              onRejected(reason);
            });
          }
          //pending状态时,将onFulfilled, onRejected存入队列
          if (this.state === "pending") {
            this.queue.push([onFulfilled, onRejected]);
          }
        });
        return p2;
      }
    }
    

    下面测试一下,then方法中的回调成功执行了,但是和正常的promise执行顺序不太一样

    console.log("1");
    var p = new MyPromise((resolve, reject) => {
      setTimeout(() => {
        console.log("2");
        resolve(4);
        console.log("3");
      });
    });
    p.then(
      (res) => {
        console.log('res',res);
      },
      () => {
        console.log("reject1");
      }
    );
    console.log("5");
    
    image.png

    测试正常promise输出的执行结果

    console.log("1");
    var p = new Promise((resolve, reject) => {
      setTimeout(() => {
        console.log("2");
        resolve(4);
        console.log("3");
      });
    });
    p.then(
      (res) => {
        console.log('res',res);
      },
      () => {
        console.log("reject1");
      }
    );
    console.log("5");
    

    可以看到resolve的执行是在最后执行的。如何让resolve在后面执行呢,很简单放到setTimeout中就行啦


    image.png
    class MyPromise {
      #status = "pending"; //规范2.1.1  初始状态为 pending
      #result = undefined; //返回结果
      //接收一个 fn 函数,
      constructor(fn) {
        this.queue = []; //添加一个队列,存储onFulfilled, onRejected
        const resolve = (data) => {
          //规范2.1.2  不能转换为其他任何状态
          if (this.#status !== "pending") return;
          setTimeout(() => {
            this.#status = "fulfilled"; //规范2.1.2  状态变为 fulfilled
            this.#result = data;
            //2.2.6.1 如果/当promise被实现时,所有相应的onFulfilled回调函数必须按照它们发起then调用的顺序执行。
            this.queue.map((callbacks) => {
              const task = callbacks[0];
              task(data);
            });
          });
        };
        //规范 2.1.3.2  有一个失败原因
        const reject = (reason) => {
          //规范2.1.3  不能转换为其他任何状态
          if (this.#status !== "pending") return;
          setTimeout(() => {
            this.#status = "rejected"; //2.1.3    状态变为 rejected
            this.#result = reason;
            //2.2.6.2 如果/当promise被拒绝时,所有相应的onRejected回调函数必须按照它们发起then调用的顺序执行。
            this.queue.map((callbacks) => {
              const task = callbacks[1];
              task(reason);
            });
          });
        };
    
        // 如果函数执行过程中出错,状态变为rejected
        try {
          // this.queue.push([resolve, reject]);
          fn(resolve, reject);
        } catch (error) {
          reject(error);
        }
      }
      //2.2.1 有一个then方法,有两个可选参数
      then(onFulfilled, onRejected) {
        //2.2.1.1 如果onFulfilled不是一个函数,它必须被忽略
        //2.2.5 onFulfilled和onRejected必须作为函数被调用(即没有this值
        const onFulfilledcallback =
          typeof onFulfilled === "function" ? onFulfilled : () => {};
        // 2.2.1.2 如果onRejected不是一个函数,它必须被忽略
        //2.2.5 onFulfilled和onRejected必须作为函数被调用(即没有this值
        const onRejectedcallback =
          typeof onRejected === "function" ? onRejected : () => {};
        //2.2.7 必须返回一个 promise
        const p2 = new MyPromise((resolve, reject) => {
        //2.2.2.2 在promise实现之前不得调用onFulfilled。
        if (this.#status === "fulfilled") {
          //2.2.4 onFulfilled或onRejected不能在执行上下文堆栈中只包含平台代码之前调用。
          setTimeout(() => {
            try {
              onFulfilledcallback(this.#result);
            } catch (e) {
              reject(e);
            }
          });
        }
        //2.2.3.2 在promise被拒绝之前不得调用它。
        if (this.#status === "rejected") {
          //2.2.2.1 它必须在promise实现后调用,并以promise的值作为其第一个参数。
          setTimeout(() => {
            try {
              onRejectedcallback(this.#result);
            } catch (e) {
              reject(e);
            }
          });
        }
        //2.2.6then方法可以在同一个promise上多次调用。
        if (this.#status === "pending") {
          this.queue.push([onFulfilled, onRejected]);
        }
        });
        return p2;
      }
      #resolutionProcedure(promise, x, resolve, reject) {
        try {
          if (promise === x) {
          }
        } catch (error) {}
      }
    }
    

    在测试一下

    console.log("1");
    var p = new MyPromise((resolve, reject) => {
      setTimeout(() => {
        console.log("2");
        resolve(4);
        console.log("3");
      });
    });
    p.then(
      (res) => {
        console.log("resolve", res);
      },
      (reason) => {
        console.log("reject", reason);
      }
    );
    console.log("5");
    

    结果和正常的promise一样了


    image.png

    我们知道then方法中onFulfilled或onRejected可以不是一个函数

    var p = new Promise((resolve,reject)=>{
      resolve(1)
    })
    p.then(undefined,reason=>{
      console.log(reason)
    }).then((res)=>{
      console.log(res)
    },undefined)
    

    需要再then方法中处理一下resolvereject的返回值

    class MyPromise {
      ...
      //2.2.1 有一个then方法,有两个可选参数
      then(onFulfilled, onRejected) {
        //2.2.1.1 如果onFulfilled不是一个函数,它必须被忽略
        //2.2.5 onFulfilled和onRejected必须作为函数被调用(即没有this值
    
        onFulfilled =
          typeof onFulfilled === "function" ? onFulfilled : (data) => data;
        // 2.2.1.2 如果onRejected不是一个函数,它必须被忽略
        //2.2.5 onFulfilled和onRejected必须作为函数被调用(即没有this值
    
        onRejected =
          typeof onRejected === "function"
            ? onRejected
            : (reason) => {
                throw reason;
              };
        //2.2.7 必须返回一个 promise
        const p2 = new MyPromise((resolve, reject) => {
          //2.2.2.2 在promise实现之前不得调用onFulfilled。
          if (this.#status === "fulfilled") {
            //2.2.4 onFulfilled或onRejected不能在执行上下文堆栈中只包含平台代码之前调用。
            setTimeout(() => {
              try {
                const x = onFulfilled(this.#result);
                this.#resolvePromise(p2, x, resolve, reject);
              } catch (e) {
                //2.2.7.2 如果onFulfilled或onRejected抛出异常e,则promise2必须以e作为原因被拒绝
                reject(e);
              }
            });
          }
          //2.2.3.2 在promise被拒绝之前不得调用它。
          if (this.#status === "rejected") {
            //2.2.2.1 它必须在promise实现后调用,并以promise的值作为其第一个参数。
            setTimeout(() => {
              try {
                const x = onRejected(this.#result);
                this.#resolvePromise(p2, x, resolve, reject);
              } catch (e) {
                //2.2.7.2 如果onFulfilled或onRejected抛出异常e,则promise2必须以e作为原因被拒绝
                reject(e);
              }
            });
          }
          //2.2.6then方法可以在同一个promise上多次调用。
          if (this.#status === "pending") {
            this.queue.push([
              () => {
                setTimeout(() => {
                  try {
                    let x = onFulfilled(this.#result);
                    this.#resolvePromise(p2, x, resolve, reject);
                  } catch (e) {
                    reject(e);
                  }
                });
              },
              () => {
                setTimeout(() => {
                  try {
                    let x = onRejected(this.#result);
                    this.#resolvePromise(p2, x, resolve, reject);
                  } catch (e) {
                    reject(e);
                  }
                });
              },
            ]);
          }
        });
        return p2;
      }
      /**
       * 对resolve()、reject() 进行改造增强 针对resolve()和reject()中不同值情况 进行处理
       * @param  {promise} promise2 promise1.then方法返回的新的promise对象
       * @param  {[type]} x         promise1中onFulfilled或onRejected的返回值
       * @param  {[type]} resolve   promise2的resolve方法
       * @param  {[type]} reject    promise2的reject方法
       */
      #resolvePromise(promise2, x, resolve, reject) {
        //2.3.1 如果promise和x引用同一个对象,则以TypeError为原因拒绝promise
        if (x === promise2) {
          return reject(new TypeError("Chaining cycle detected for promise"));
        }
        //2.3.2 如果x是一个promise,采用其状态
        if (x instanceof MyPromise) {
          if (x.#status === "pending") {
            x.then(
              (y) => {
                this.#resolvePromise(promise2, y, resolve, reject);
              },
              () => {
                reject(x.#result);
              }
            );
          }
          if (x.#status === "fulfilled") {
            resolve(x.#result);
          }
          if (x.#status === "rejected") {
            reject(x.#result);
          }
        }
        //2.3.3 否则,如果x是一个对象或函数:
        //注意x不能为null
        else if (x !== null && (x instanceof Object || typeof x === "function")) {
          try {
            //2.3.3.2
            var then = x.then;
          } catch (e) {
            //2.3.3.3
            reject(e);
          }
          if (typeof then === "function") {
            //定义called表示y,r是否被调用过
            let called = false;
            //2.3.3.3.4
            try {
              then.call(
                x,
                //2.3.3.3.1
                (y) => {
                  //2.3.3.3.3
                  if (called) return;
                  this.#resolvePromise(p2, y, resolve, reject);
                  called = true;
                },
                //2.3.3.3.2
                (r) => {
                  //2.3.3.3.3
                  if (called) return;
                  reject(r);
                  called = true;
                }
              );
            } catch (e) {
              //2.3.3.3.4.1
              if (called) return;
              //2.3.3.3.4.2
              reject(e);
            }
          } else {
            resolve(x);
          }
        }
        //2.3.4 如果x不是对象或函数,则用x来实现promise。
        else {
          resolve(x);
        }
        try {
        } catch (error) {}
      }
    }
    

    实现链式调用

    上面代码中then方法返回一个promsie,那么onFulFilled和onReject的结果如何处理呢?
    参考promise a+规范2.2.7

    • 2.2.7.1如果onFulfilled或onRejected返回一个值x,则运行Promise Resolution Procedure [[Resolve]](promise2, x)。
    • 2.2.7.2 如果onFulfilled或onRejected抛出异常e,则promise2必须以e作为原因被拒绝。
    • 2.2.7.3 如果onFulfilled不是一个函数且promise1被实现,则promise2必须以与promise1相同的值被实现。
    • 2.2.7.4 如果onRejected不是一个函数且promise1被拒绝,则promise2必须以与promise1相同的原因被拒绝。
      这里我们定义个函数resolvePromise(promise,x resolve,reject) 来处理x,在then方法中分别在不同状态下用resolvePromise方法处理
    class MyPromise {
     ...
      //2.2.1 有一个then方法,有两个可选参数
      then(onFulfilled, onRejected) {
        //2.2.1.1 如果onFulfilled不是一个函数,它必须被忽略
        //2.2.5 onFulfilled和onRejected必须作为函数被调用(即没有this值
    
        onFulfilled = typeof onFulfilled === "function" ? onFulfilled : () => {};
        // 2.2.1.2 如果onRejected不是一个函数,它必须被忽略
        //2.2.5 onFulfilled和onRejected必须作为函数被调用(即没有this值
    
        onRejected = typeof onRejected === "function" ? onRejected : () => {};
        //2.2.7 必须返回一个 promise
        const p2 = new MyPromise((resolve, reject) => {
          //2.2.2.2 在promise实现之前不得调用onFulfilled。
          if (this.#status === "fulfilled") {
            //2.2.4 onFulfilled或onRejected不能在执行上下文堆栈中只包含平台代码之前调用。
            setTimeout(() => {
              try {
                const x = onFulfilled(this.#result);
                this.#resolvePromise(p2, x, resolve, reject);
              } catch (e) {
                //2.2.7.2 如果onFulfilled或onRejected抛出异常e,则promise2必须以e作为原因被拒绝
                reject(e);
              }
            });
          }
          //2.2.3.2 在promise被拒绝之前不得调用它。
          if (this.#status === "rejected") {
            //2.2.2.1 它必须在promise实现后调用,并以promise的值作为其第一个参数。
            setTimeout(() => {
              try {
                const x = onRejected(this.#result);
                this.#resolvePromise(p2, x, resolve, reject);
              } catch (e) {
                //2.2.7.2 如果onFulfilled或onRejected抛出异常e,则promise2必须以e作为原因被拒绝
                reject(e);
              }
            });
          }
          //2.2.6then方法可以在同一个promise上多次调用。
          if (this.#status === "pending") {
            this.queue.push([
              () => {
                setTimeout(() => {
                  try {
                    let x = onFulfilled(this.#result);
                    this.#resolvePromise(p2, x, resolve, reject);
                  } catch (e) {
                    reject(e);
                  }
                });
              },
              () => {
                setTimeout(() => {
                  try {
                    let x = onRejected(this.#result);
                    this.#resolvePromise(p2, x, resolve, reject);
                  } catch (e) {
                    reject(e);
                  }
                });
              },
            ]);
          }
        });
        return p2;
      }
      /**
       * 对resolve()、reject() 进行改造增强 针对resolve()和reject()中不同值情况 进行处理
       * @param  {promise} promise2 promise1.then方法返回的新的promise对象
       * @param  {[type]} x         promise1中onFulfilled或onRejected的返回值
       * @param  {[type]} resolve   promise2的resolve方法
       * @param  {[type]} reject    promise2的reject方法
       */
      #resolvePromise(promise2, x, resolve, reject) {
        
      }
    }
    

    按照下面规范实现resolvePromise


    image.png
    /**
       * 对resolve()、reject() 进行改造增强 针对resolve()和reject()中不同值情况 进行处理
       * @param  {promise} promise2 promise1.then方法返回的新的promise对象
       * @param  {[type]} x         promise1中onFulfilled或onRejected的返回值
       * @param  {[type]} resolve   promise2的resolve方法
       * @param  {[type]} reject    promise2的reject方法
       */
    #resolvePromise(promise2, x, resolve, reject) {
        //2.3.1 如果promise和x引用同一个对象,则以TypeError为原因拒绝promise
        if (x === promise2) {
          return reject(new TypeError("Chaining cycle detected for promise"));
        }
        //2.3.2 如果x是一个promise,采用其状态
        if (x instanceof MyPromise) {
          if (x.#status === "pending") {
            x.then(
              (y) => {
                this.#resolvePromise(promise2, y, resolve, reject);
              },
              () => {
                reject(x.#result);
              }
            );
          }
          if (x.#status === "fulfilled") {
            resolve(x.#result);
          }
          if (x.#status === "rejected") {
            reject(x.#result);
          }
        }
        //2.3.3 否则,如果x是一个对象或函数:
        //注意x不能为null
        else if (x !== null && (typeof x === "object" || typeof x === "function")) {
          var then;
          try {
            //2.3.3.2
            then = x.then;
            if (typeof then === "function") {
              //定义called表示y,r是否被调用过
              let called = false;
              //2.3.3.3.4
              try {
                then.call(
                  x,
                  //2.3.3.3.1
                  (y) => {
                    //2.3.3.3.3
                    if (called) return;
                    called = true;
                    this.#resolvePromise(promise2, y, resolve, reject);
                  },
                  //2.3.3.3.2
                  (r) => {
                    //2.3.3.3.3
                    if (called) return;
                    called = true;
                    reject(r);
                  }
                );
              } catch (e) {
                //2.3.3.3.4.1
                if (called) return;
                //2.3.3.3.4.2
                reject(e);
              }
            } else {
              resolve(x);
            }
          } catch (e) {
            //2.3.3.3
            reject(e);
          }
        }
        //2.3.4 如果x不是对象或函数,则用x来实现promise。
        else {
          resolve(x);
        }
      }
    

    下面测试一下

    console.log("1");
    var p = new MyPromise((resolve, reject) => {
      setTimeout(() => {
        console.log("2");
        resolve(4);
        console.log("3");
      });
    });
    p.then(
      (res) => {
        console.log("resolve1", res);
        return new MyPromise((resolve, reject) => {
          resolve(123);
        });
      },
      (reason) => {
        console.log("reject1", reason);
      }
    ).then(
      (res) => {
        console.log("resolve2", res);
      },
      (reason) => {
        console.log("reject2", reason);
      }
    );
    console.log("5");
    

    可以看到结果和替换成官方Promise的结果一致


    image.png
    image.png

    相关文章

      网友评论

          本文标题:Promise是什么,如何手写一个符合 PromiseA+规范的

          本文链接:https://www.haomeiwen.com/subject/jbtacjtx.html