> 文章列表 > js基础之Promise(全面+手写实现)

js基础之Promise(全面+手写实现)

js基础之Promise(全面+手写实现)

1. 是什么

Promise是一种异步编程的解决方案,用于处理异步操作并返回结果。
主要作用是解决回调函数嵌套(回调地狱)的问题,使异步操作更加清晰、易于理解和维护。

2. 怎么用

Promise有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。当一个Promise被创建时,它的状态为pending。当异步操作完成并成功时,Promise的状态会变为fulfilled,并返回一个结果。当异步操作失败时,Promise的状态会变为rejected,并返回一个错误信息。

基本语法

// 创建一个promise
let promise = new Promise(function(resolve, reject) {// 异步操作if (异步操作成功) {resolve(value); // 将异步操作的结果传递给Promise对象,状态变为fulfilled} else {reject(error); // 将异步操作的错误信息传递给Promise对象,状态变为rejected}
});promise.then(function(result) {// 异步操作成功时的处理代码
}).catch(function(error) {// 异步操作失败时的处理代码
});

常用方法

  1. then
    then中一般传入两个参数(函数),第一个对应resolve成功的回调,第二个对应reject失败的回调,如下

    
    function onResolved(res) {console.log("resolved-" + res); // resolved-成功了
    }
    function onRejected(err) {console.log("rejected-" + err); // rejected-失败了
    }new Promise((resolve, reject) => {resolve('成功了');// reject('失败了')
    }).then(onResolved, onRejected);
    

    then的第二个参数就等同于catch方法,但是需要注意

    • Promise内部报错,reject抛出错误后,then的第二个参数和catch方法都存在的情况下,只有then的第二个参数能捕获到,如果then的第二个参数不存在,catch方法会捕捉到
    • catch不仅捕捉promise中抛出的错误,还会捕捉前面then中的错误
  2. catch
    捕捉promise错误函数,和then的第二个参数(函数)作用一样,处理错误,由于Promise抛出错误具有冒泡性质,能够不断传递,会传到catch中,所以一般来说所有错误处理放在catch中,then中只处理成功的,同时catch还会捕捉then中第一个参数(函数)抛出的异常

    new Promise((resolve, reject) => {reject();
    }).catch((err)=> {console.log(err)
    });
    
  3. finally
    finally 方法没有参数,也不会改变 Promise 的状态,它只是在 Promise 结束时提供了一个通知机制,让我们可以在 Promise 结束后执行一些清理工作(比如操作文件的时候关闭文件流)。

    function onFinally() {console.log('结束');
    }
    new Promise((resolve, reject) => {}).finally(onFinally);
    
  4. all
    接受一个具有Iterable接口的类型,如数组,Map,Set,传入多个promise,
    每一个promise执行成功resolve,最后才执行成功(返回一个Promise实例),进入then,否则失败进入catch

    function p1() {var promise1 = new Promise(function (resolve, reject) {console.log("p1的第一条输出语句");resolve("p1完成");});return promise1;
    }function p2() {var promise2 = new Promise(function (resolve, reject) {console.log("p2的第一条输出语句");setTimeout(() => {console.log("p2的第二条输出语句");resolve("p2完成");}, 2000);});return promise2;
    }function p3() {var promise3 = new Promise(function (resolve, reject) {console.log("p3的第一条输出语句");resolve("p3完成");});return promise3;
    }Promise.all([p1(), p2(), p3()]).then(function (data) {console.log(data);
    });// 输出
    // p1的第一条输出语句;
    // p2的第一条输出语句;
    // p3的第一条输出语句;
    // p2的第二条输出语句[("p1完成", "p2完成", "p3完成")];var p1 = new Promise((resolve, reject) => {setTimeout(resolve, 1000, 'one');
    });
    var p2 = new Promise((resolve, reject) => {setTimeout(resolve, 2000, 'two');
    });
    var p3 = new Promise((resolve, reject) => {setTimeout(resolve, 3000, 'three');
    });
    var p4 = new Promise((resolve, reject) => {setTimeout(resolve, 4000, 'four');
    });
    var p5 = new Promise((resolve, reject) => {reject('reject');// setTimeout(resolve, 5000, 'five');
    });
    Promise.all([p1, p2, p3, p4, p5]).then(values => {console.log(values); // [ 'one', 'two', 'three', 'four', 'five' ]
    }, reason => {console.log(reason) // reject
    });
    
  5. allSettled
    接受一个具有Iterable接口的类型,如数组,Map,Set,传入多个promise,
    每个promise状态改变成fulfilled或者rejected之后返回,返回的是一个数组对象,对象中有状态status和每一项的返回结果value

    Promise.allSettled([p1, p2, p3, p4, p5]).then(values => {console.log(values);
    }, reason => {console.log(reason)
    });
    // [
    //   { status: 'fulfilled', value: 'one' },
    //   { status: 'fulfilled', value: 'two' },
    //   { status: 'fulfilled', value: 'three' },
    //   { status: 'fulfilled', value: 'four' },
    //   { status: 'rejected', reason: 'reject' }
    // ]
    
  6. race
    以快为准,数组中所有的promise对象,有一个先执行了何种状态,该对象就为何种状态,并执行相应函数
    接受一个具有Iterable接口的类型,如数组,Map,Set,传入多个promise,
    其中有一个promise返回了,不管是fulfilled或者rejected,直接返回这个promise的结果

    function p1() {var promise1 = new Promise(function (resolve, reject) {console.log("p1的第一条输出语句");resolve("p1完成");});return promise1;
    }function p2() {var promise2 = new Promise(function (resolve, reject) {console.log("p2的第一条输出语句");setTimeout(() => {console.log("p2的第二条输出语句");resolve("p2完成");}, 2000);});return promise2;
    }function p3() {var promise3 = new Promise(function (resolve, reject) {console.log("p3的第一条输出语句");resolve("p3完成");});return promise3;
    }Promise.race([p1(), p2(), p3()]).then(function (data) {console.log(data);
    });// 输出
    // p1的第一条输出语句
    // p2的第一条输出语句
    // p3的第一条输出语句
    // p1完成
    
  7. any
    接受一个具有Iterable接口的类型,如数组,Map,Set,传入多个promise,
    当传入的任何一个promise成功的时候,不管其他是否成功或者失败,会把成功的那个promise返回

如果传入的是一个空的数组(Map,Set),返回一个已失败状态的promise,如下
在这里插入图片描述

注意

Promise的以上方法都属于 微任务。当Promise状态变为已解决(resolved)或被拒绝(rejected)时,这些方法会产生微任务。这些微任务会在主线程空闲时按照顺序依次执行。

3. 有什么问题

  • 首先,无法取消 Promise,一旦新建它就会立即执行,无法中途取消。
  • 其次,如果不设置回调函数,Promise 内部抛出的错误,不会反应到外部。
  • 第三,当处于 Pending 状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。

4. 手写实现

手写实现有助于我们更好的理解Promise,开始吧!

我们使用Es6类的方式,构建一个Promise,更直观好理解

基本实现

  • 先写出一个雏形,维护三种状态,并定义reslove、reject、和then方法

    class MyPromise {static PENDING = "等待";static FULFILLED = "成功";static REJECTED = "失败";constructor(func) {this.status = MyPromise.PENDING; // 定义状态this.result = null; // 定义返回结果func(this.reslove.bind(this), this.reject.bind(this)); // 执行传入的函数}reslove(result) {this.status = MyPromise.FULFILLED; // 更改状态this.result = result;}reject(result) {this.status = MyPromise.FULFILLED; // 更改状态this.result = result;}then(onFULFILLED, onREJECTED) {if (this.status === MyPromise.FULFILLED) {// 执行成功后的回调onFULFILLED()}if (this.status === MyPromise.REJECTED) {// 执行失败后的回调onREJECTED()}}
    }
    
  • 注意

    当Promise中抛出错误时,会把promise的状态改为失败并且将错误设置为结果,如下

    const p = new Promise((resolve,reject)=> {throw new Error('出错')
    })
    p.then((res)=> {console.log(res)
    },(err)=> {console.log(err.message) // log: 出错
    })
    

    then中两个参数可以传入undefined

    const p = new Promise((resolve,reject)=> {resolve('成功')
    })
    p.then(undefined,(err)=> {console.log(err)
    })
    

    完善一下上面的两个问题,代码如下

    class MyPromise {static PENDING = "等待";static FULFILLED = "成功";static REJECTED = "失败";constructor(func) {this.status = MyPromise.PENDING; // 定义状态this.result = null; // 定义返回结果// 当Promise中抛出错误时,会把promise的状态改为失败并且将错误设置为结果try {func(this.reslove.bind(this), this.reject.bind(this)); // 执行传入的函数} catch (err) {this.reject(err);}}reslove(result) {this.status = MyPromise.FULFILLED; // 更改状态this.result = result;}reject(result) {this.status = MyPromise.FULFILLED; // 更改状态this.result = result;}then(onFULFILLED, onREJECTED) {// then中两个参数可以传入undefined,做下处理onFULFILLED =typeof onFULFILLED === "function"? onFULFILLED: (value) => {value;};onREJECTED =typeof onREJECTED === "function"? onREJECTED: (reason) => {throw reason;};if (this.status === MyPromise.FULFILLED) {// 执行成功后的回调onFULFILLED(this.result);}if (this.status === MyPromise.REJECTED) {// 执行失败后的回调onREJECTED(this.result);}}
    }
  • 继续完善
    我们先写一个真实promises,看一下下面代码的执行顺序

    console.log('第一步')
    const p = new Promise((resolve,reject)=> {console.log('第二步')setTimeout(() => {resolve('成功')console.log('第四步')});
    })
    p.then((res)=> {console.log(res)
    },(err)=> {console.log(err)
    })
    console.log('第三步')
    // 依次输出如下:
    // 第一步
    // 第二步
    // 第三步
    // 第四步
    // 成功
    

    可以看到,then里面的代码是最后执行的,then属于微任务,resolve和reject 属于在事件循环末尾执行的,因此完善一下实现代码

    class MyPromise {static PENDING = "等待";static FULFILLED = "成功";static REJECTED = "失败";constructor(func) {this.status = MyPromise.PENDING; // 定义状态this.result = null; // 定义返回结果this.resloveCallbacks = []; // 存放reslove回调函数的数组this.rejectCallbacks = []; // 存放reject回调函数的数组// 当Promise中抛出错误时,会把promise的状态改为失败并且将错误设置为结果try {func(this.reslove.bind(this), this.reject.bind(this)); // 执行传入的函数} catch (err) {this.reject(err);}}reslove(result) { // resolve是在事件循环末尾执行的,所以这里用setTimeout包裹一下setTimeout(() => {this.status = MyPromise.FULFILLED; // 更改状态this.result = result;// 遍历执行PENDING状态时保存的reslove回调函数this.resloveCallbacks.forEach((callback) => {callback(result);});});}reject(result) {// reject同样用setTimeout包裹一下setTimeout(() => {this.status = MyPromise.FULFILLED; // 更改状态this.result = result;// 遍历执行PENDING状态时保存的reject回调函数this.rejectCallbacks.forEach((callback) => {callback(result);});});}then(onFULFILLED, onREJECTED) {// then中两个参数可以传入undefined,做下处理onFULFILLED =typeof onFULFILLED === "function"? onFULFILLED: (value) => {value;};onREJECTED =typeof onREJECTED === "function"? onREJECTED: (reason) => {throw reason;};if (this.status === MyPromise.PENDING) {// PENDING状态时this.resloveCallbacks.push(onFULFILLED);this.rejectCallbacks.push(onREJECTED);}if (this.status === MyPromise.FULFILLED) {setTimeout(() => {// 执行成功后的回调onFULFILLED(this.result);})}if (this.status === MyPromise.REJECTED) {setTimeout(() => {// 执行失败后的回调onREJECTED(this.result);})}}
    }

    OK,到此我们可以测试一下

    console.log('第一步')
    const p = new MyPromise((resolve,reject)=> {console.log('第二步')setTimeout(() => {resolve('成功')console.log('第四步')});
    })
    p.then((res)=> {console.log(res)
    },(err)=> {console.log(err)
    })
    console.log('第三步')
    // 第一步
    // 第二步
    // 第三步
    // 第四步
    // 成功
    

实现then

  • 下面进入重头戏-----then的 链式调用
    先看一下示例,如下

    const p = new Promise((resolve, reject) => {setTimeout(() => {resolve("成功");});
    });
    p.then((res) => {console.log("第一次then", res);return '返回一个正常值'// return new Promise((resolve)=> {//   setTimeout(() => {//     resolve('返回一个promise')//   });// })// throw "抛出一个异常"
    }).then((res) => {console.log("第二次then", res);},(err) => {console.log("第二次then", err);}
    );
    // 第一次then 成功
    // 第二次then 返回一个正常值 | 第二次then 返回一个promise |第二次then 抛出一个异常
    

    如果 then 返回的是一个正常值,那么就会把这个结果(value)作为参数,传递给下一个 then 的成功的回调(onFULFILLED);
    如果 then 中抛出了异常,那么就会把这个异常(reason)作为参数,传递给下一个 then 的失败的回调(onREJECTED);
    如果 then 返回的是一个 promise 或者其他 thenable 对象,那么需要等这个 promise 执行完成,promise 如果成功,就走下一个 then 的成功回调;如果失败,就走下一个 then 的失败回调

    要实现上面功(链式调用),我们需要在then方法中,返回一个 promise

      then(onFULFILLED, onREJECTED) {let newPromise = new MyPromise((resolve, reject) => {// then中两个参数可以传入undefined,做下处理onFULFILLED =typeof onFULFILLED === "function"? onFULFILLED: (value) => {value;};onREJECTED =typeof onREJECTED === "function"? onREJECTED: (reason) => {throw reason;};if (this.status === MyPromise.PENDING) {// PENDING状态时this.resloveCallbacks.push(() => {try {let nextResult = onFULFILLED(this.result);resolve(nextResult)} catch (err) {reject(err);}});this.rejectCallbacks.push(() => {try {let nextResult = onREJECTED(this.result);resolve(nextResult)} catch (err) {reject(err);}});}if (this.status === MyPromise.FULFILLED) {setTimeout(() => {try {// 执行成功后的回调let nextResult = onFULFILLED(this.result);resolve(nextResult)} catch (err) {reject(err);}});}if (this.status === MyPromise.REJECTED) {setTimeout(() => {try {// 执行失败后的回调let nextResult = onREJECTED(this.result);resolve(nextResult)} catch (err) {reject(err);}});}});return newPromise;}
    

    这时我们测试一下,已经能实现链式调用了

    const p = new MyPromise((resolve, reject) => {setTimeout(() => {resolve("成功");});
    });
    p.then((res) => {console.log("第一次then", res);return "返回一个正常值";
    }).then((res) => {console.log("第二次then", res);},(err) => {console.log("第二次then", err);}
    );
    // 第一次then 成功
    // 第二次then 返回一个正常值
    

    这样就完成了吗?并没有
    上面我们的then执行回调的地方,我们获取到回调执行结果之后就直接resolve出去了,如下

    try {let nextResult = onFULFILLED(this.result);resolve(nextResult)
    } catch (err) {reject(err);
    }
    

    对于我们上面例子,直接返回一个基本数据类型(“返回一个正常值”)是可以实现的,
    但是回调执行返回的结果,还可能存在其他类型,比如返回一个函数或者返回一个promise,或者失败抛出一个错误等等,对于这些情况,我们也需要进行处理

  • 完善then的链式调用-----处理then中返回
    我们封装一个resolvePromise方法,用来处理不同情况

    then(onFULFILLED, onREJECTED) {let newPromise = new MyPromise((resolve, reject) => {// then中两个参数可以传入undefined,做下处理onFULFILLED =typeof onFULFILLED === "function"? onFULFILLED: (value) => {value;};onREJECTED =typeof onREJECTED === "function"? onREJECTED: (reason) => {throw reason;};if (this.status === MyPromise.PENDING) {// PENDING状态时this.resloveCallbacks.push(() => {try {let nextResult = onFULFILLED(this.result);resolvePromise(newPromise, nextResult, resolve, reject);} catch (err) {reject(err);}});this.rejectCallbacks.push(() => {try {let nextResult = onREJECTED(this.result);resolvePromise(newPromise, nextResult, resolve, reject);} catch (err) {reject(err);}});}if (this.status === MyPromise.FULFILLED) {setTimeout(() => {try {// 执行成功后的回调let nextResult = onFULFILLED(this.result);resolvePromise(newPromise, nextResult, resolve, reject);} catch (err) {reject(err);}});}if (this.status === MyPromise.REJECTED) {setTimeout(() => {try {// 执行失败后的回调let nextResult = onREJECTED(this.result);resolvePromise(newPromise, nextResult, resolve, reject);} catch (err) {reject(err);}});}});return newPromise;
    }
    

    根据promise规范,实现的resolvePromise

    function resolvePromise(newPromise, x, resolve, reject) {if (x === newPromise) {// 因为x是回调的结果值,如果x指向newPromise即自己,那么会重新解析自己,导致循环调用throw new TypeError("禁止循环调用");}// 如果x是一个Promise,我们必须等它完成(失败或成功)后得到一个普通值时,才能继续执行。// 那我们把要执行的任务放在x.then()的成功回调和失败回调里面即可// 这就表示x完成后就会调用我们的代码。// 但是对于成功的情况,我们还需要再考虑下,x.then成功回调函数的参数,我们称为y// 那y也可能是一个thenable对象或者promise// 所以如果成功时,执行resolvePromise(promise2, y, resolve, reject)// 并且传入resolve, reject,当解析到普通值时就resolve出去,反之继续解析// 这样子用于保证最后resolve的结果一定是一个非promise类型的参数if (x instanceof MyPromise) {x.then((y) => {resolvePromise(newPromise, y, resolve, reject);},(r) => reject(r));}// (x instanceof myPromise) 处理了promise的情况,但是很多时候交互的promise可能不是原生的// 就像我们现在写的一个myPromise一样,这种有then方法的对象或函数我们称为thenable。// 因此我们需要处理thenable。else if ((typeof x === "object" || typeof x === "function") && x !== null) {// 暂存x这个对象或函数的then,x也可能没有then,那then就会得到一个undefinedtry {var then = x.then;} catch (e) {// 如果读取then的过程中出现异常则reject异常出去return reject(e);}// 判断then是否函数且存在,如果函数且存在那这个就是合理的thenable,我们要尝试去解析if (typeof then === "function") {// 状态只能更新一次使用一个called防止反复调用// 因为成功和失败的回调只能执行其中之一let called = false;try {then.call(x,(y) => {// called就是用于防止成功和失败被同时执行,因为这个是thenable,不是promise// 需要做限制如果newPromise已经成功或失败了,则不会再处理了if (called) return;called = true;resolvePromise(newPromise, y, resolve, reject);},(r) => {// called就是用于防止成功和失败被同时执行,因为这个是thenable,不是promise// 需要做限制如果newPromise已经成功或失败了,则不会再处理了if (called) return;called = true;reject(r);});// 上面那一步等价于,即这里把thenable当作类似于promise的对象去执行then操作// x.then(//   (y) => {//     if (called) return;//     called = true;//     resolvePromise(newPromise, y, resolve, reject);//   },//   (r) => {//     if (called) return;//     called = true;//     reject(r);//   }// )} catch (e) {// called就是用于防止成功和失败被同时执行,因为这个是thenable,不是promise// 需要做限制如果newPromise已经成功或失败了,则不会再处理了if (called) return;called = true;reject(e);}} else {// 如果是对象或函数但不是thenable(即没有正确的then属性)// 当成普通值则直接resolve出去resolve(x);}} else {return resolve(x);}
    }
    

    测试一下

    const p = new MyPromise((resolve, reject) => {setTimeout(() => {resolve("成功");});
    });
    p.then((res) => {console.log("第一次then", res);// return "返回一个正常值"; // 第二次then  返回一个正常值// return new MyPromise((resolve) => {//   setTimeout(() => {//     resolve("返回一个promise"); // 第二次then 返回一个promise//   });// });throw "抛出一个异常"; // 第二次then 抛出一个异常
    }).then((res) => {console.log("第二次then", res);},(err) => {console.log("第二次then", err);}
    );
    

实现catch

  • 上面使用的时候介绍过,catch和then的第二个参数作用一样,所以catch的实现可以基于then

    catch(onREJECTED) {return this.then(null, onREJECTED);
    }
    

    测试一下,是没有问题的

    const p = new MyPromise((resolve, reject) => {setTimeout(() => {resolve("成功了");// reject('失败了')});
    });
    p.then((res) => {console.log("成功", res)throw '出错'
    }).catch((err) => {console.log("失败", err);
    });
    

实现finally

  • 当状态变化(等待变为成功或者失败)时都会进入finally,所以,依然可以借助then实现

    const p = new Promise((resolve, reject) => {setTimeout(() => {resolve(123);});
    });
    p.finally(() => {console.log('结束'); // 结束
    });
    

实现all

  • 该方法接收一个 Promise 数组(具有 Iterator 接口的对象),返回一个新的 Promise,该 Promise 在所有 Promise 都 resolve 后 resolve,如果其中有一个 Promise reject,则该 Promise 直接 reject。

    static all(promises) {return new MyPromise((resolve, reject) => {// 创建一个空数组results,用于存储每个Promise的 resolve 结果const results = [];let count = 0;const processResult = (index, result) => {// 结果存入results数组(具有Iterator接口的对象)中,并更新count变量results[index] = result;count++;if (count === promises.length) {// 如果count等于Promise 数组(具有Iterator接口的对象)的长度,则说明所有Promise都resolve了,此时调用 resolve 方法resolve(results);}};// 遍历传入的Promise数组(具有 Iterator 接口的对象),对每个Promise调用then方法for (const [index, promise] of [...promises].entries()) {MyPromise.resolve(promise).then((result) => {processResult(index, result);}, reject);}});
    }
    

    测试一下,没问题

    function p1() {var promise1 = new MyPromise(function (resolve, reject) {console.log("p1的第一条输出语句");resolve("p1完成");});return promise1;
    }function p2() {var promise2 = new MyPromise(function (resolve, reject) {console.log("p2的第一条输出语句");setTimeout(() => {console.log("p2的第二条输出语句");resolve("p2完成");}, 2000);});return promise2;
    }function p3() {var promise3 = new MyPromise(function (resolve, reject) {console.log("p3的第一条输出语句");resolve("p3完成");});return promise3;
    }
    MyPromise.all([p1(), p2(), p3()]).then(function (data) {console.log(data);
    });
    // 输出
    // p1的第一条输出语句;
    // p2的第一条输出语句;
    // p3的第一条输出语句;
    // p2的第二条输出语句[("p1完成", "p2完成", "p3完成")];
    
    var p1 = new MyPromise((resolve, reject) => {setTimeout(resolve, 1000, 'one');
    });
    var p2 = new MyPromise((resolve, reject) => {setTimeout(resolve, 2000, 'two');
    });
    var p3 = new MyPromise((resolve, reject) => {setTimeout(resolve, 3000, 'three');
    });
    var p4 = new MyPromise((resolve, reject) => {setTimeout(resolve, 4000, 'four');
    });
    var p5 = new MyPromise((resolve, reject) => {// reject('reject');setTimeout(resolve, 5000, 'five');
    });
    MyPromise.all([p1, p2, p3, p4, p5]).then(values => {console.log(values); // [ 'one', 'two', 'three', 'four', 'five' ]
    }, reason => {console.log(reason) // reject
    });
    // 5s后输出 [ 'one', 'two', 'three', 'four', 'five' ]
    

全部代码

class MyPromise {static PENDING = "等待";static FULFILLED = "成功";static REJECTED = "失败";constructor(func) {this.status = MyPromise.PENDING; // 定义状态this.result = null; // 定义返回结果this.resloveCallbacks = []; // 存放reslove回调函数的数组this.rejectCallbacks = []; // 存放reject回调函数的数组// 当Promise中抛出错误时,会把promise的状态改为失败并且将错误设置为结果try {func(this.reslove.bind(this), this.reject.bind(this)); // 执行传入的函数} catch (err) {this.reject(err);}}reslove(result) {// resolve是在事件循环末尾执行的,所以这里用setTimeout包裹一下setTimeout(() => {this.status = MyPromise.FULFILLED; // 更改状态this.result = result;// 遍历执行PENDING状态时保存的reslove回调函数this.resloveCallbacks.forEach((callback) => {callback(result);});});}reject(result) {// reject同样用setTimeout包裹一下setTimeout(() => {this.status = MyPromise.FULFILLED; // 更改状态this.result = result;// 遍历执行PENDING状态时保存的reject回调函数this.rejectCallbacks.forEach((callback) => {callback(result);});});}then(onFULFILLED, onREJECTED) {let newPromise = new MyPromise((resolve, reject) => {// then中两个参数可以传入undefined,做下处理onFULFILLED =typeof onFULFILLED === "function"? onFULFILLED: (value) => {value;};onREJECTED =typeof onREJECTED === "function"? onREJECTED: (reason) => {throw reason;};if (this.status === MyPromise.PENDING) {// PENDING状态时this.resloveCallbacks.push(() => {try {let nextResult = onFULFILLED(this.result);resolvePromise(newPromise, nextResult, resolve, reject);} catch (err) {reject(err);}});this.rejectCallbacks.push(() => {try {let nextResult = onREJECTED(this.result);resolvePromise(newPromise, nextResult, resolve, reject);} catch (err) {reject(err);}});}if (this.status === MyPromise.FULFILLED) {setTimeout(() => {try {// 执行成功后的回调let nextResult = onFULFILLED(this.result);resolvePromise(newPromise, nextResult, resolve, reject);} catch (err) {reject(err);}});}if (this.status === MyPromise.REJECTED) {setTimeout(() => {try {// 执行失败后的回调let nextResult = onREJECTED(this.result);resolvePromise(newPromise, nextResult, resolve, reject);} catch (err) {reject(err);}});}});return newPromise;}catch(onREJECTED) {return this.then(null, onREJECTED);}finally() {return this.then(undefined, undefined);}static resolve(value) {return new MyPromise((resolve) => {resolve(value);});}static reject(reason) {return new MyPromise((resolve, reject) => {reject(reason);});}static all(promises) {return new MyPromise((resolve, reject) => {// 创建一个空数组results,用于存储每个Promise的 resolve 结果const results = [];let count = 0;const processResult = (index, result) => {// 结果存入results数组(具有Iterator接口的对象)中,并更新count变量results[index] = result;count++;if (count === promises.length) {// 如果count等于Promise 数组(具有Iterator接口的对象)的长度,则说明所有Promise都resolve了,此时调用 resolve 方法resolve(results);}};// 遍历传入的Promise数组(具有 Iterator 接口的对象),对每个Promise调用then方法for (const [index, promise] of [...promises].entries()) {Promise.resolve(promise).then((result) => {processResult(index, result);}, reject);}});}
}function resolvePromise(newPromise, x, resolve, reject) {if (x === newPromise) {// 因为x是回调的结果值,如果x指向newPromise即自己,那么会重新解析自己,导致循环调用throw new TypeError("禁止循环调用");}// 如果x是一个Promise,我们必须等它完成(失败或成功)后得到一个普通值时,才能继续执行。// 那我们把要执行的任务放在x.then()的成功回调和失败回调里面即可// 这就表示x完成后就会调用我们的代码。// 但是对于成功的情况,我们还需要再考虑下,x.then成功回调函数的参数,我们称为y// 那y也可能是一个thenable对象或者promise// 所以如果成功时,执行resolvePromise(promise2, y, resolve, reject)// 并且传入resolve, reject,当解析到普通值时就resolve出去,反之继续解析// 这样子用于保证最后resolve的结果一定是一个非promise类型的参数if (x instanceof MyPromise) {x.then((y) => {resolvePromise(newPromise, y, resolve, reject);},(r) => reject(r));}// (x instanceof myPromise) 处理了promise的情况,但是很多时候交互的promise可能不是原生的// 就像我们现在写的一个myPromise一样,这种有then方法的对象或函数我们称为thenable。// 因此我们需要处理thenable。else if ((typeof x === "object" || typeof x === "function") && x !== null) {// 暂存x这个对象或函数的then,x也可能没有then,那then就会得到一个undefinedtry {var then = x.then;} catch (e) {// 如果读取then的过程中出现异常则reject异常出去return reject(e);}// 判断then是否函数且存在,如果函数且存在那这个就是合理的thenable,我们要尝试去解析if (typeof then === "function") {// 状态只能更新一次使用一个called防止反复调用// 因为成功和失败的回调只能执行其中之一let called = false;try {then.call(x,(y) => {// called就是用于防止成功和失败被同时执行,因为这个是thenable,不是promise// 需要做限制如果newPromise已经成功或失败了,则不会再处理了if (called) return;called = true;resolvePromise(newPromise, y, resolve, reject);},(r) => {// called就是用于防止成功和失败被同时执行,因为这个是thenable,不是promise// 需要做限制如果newPromise已经成功或失败了,则不会再处理了if (called) return;called = true;reject(r);});// 上面那一步等价于,即这里把thenable当作类似于promise的对象去执行then操作// x.then(//   (y) => {//     if (called) return;//     called = true;//     resolvePromise(newPromise, y, resolve, reject);//   },//   (r) => {//     if (called) return;//     called = true;//     reject(r);//   }// )} catch (e) {// called就是用于防止成功和失败被同时执行,因为这个是thenable,不是promise// 需要做限制如果newPromise已经成功或失败了,则不会再处理了if (called) return;called = true;reject(e);}} else {// 如果是对象或函数但不是thenable(即没有正确的then属性)// 当成普通值则直接resolve出去resolve(x);}} else {return resolve(x);}
}