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

什么是 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
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,636评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,890评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,680评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,766评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,665评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,045评论 1 276
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,515评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,182评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,334评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,274评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,319评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,002评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,599评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,675评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,917评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,309评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,885评论 2 341

推荐阅读更多精彩内容