「JS硬气功👊」Promise异步移形换影——下(Promise静态API实现:包含resolve、reject、all、race)

251 阅读4分钟

Hi! 这里是JustHappy,既然点开了这个JS硬气功,那就一起愉快的修炼吧!我想大家和我一样,在面试中遇到Primise手写题这类的总是想不起来,所以这次我们尝试使用JS硬气功暴打一下,话不多说,我们继续吧。

image.png

Promise.resolve() 和 Promise.reject()

这两个方法实际上很简单,和我们之前实现链式调用的 .catch 一样,都像是语法糖,很简单,只需要返回对应的MyPromise对象就行,就像下面这样,每个都只要一行代码

MyPromise.resolve = function (value) {
    return new MyPromise((resolve,reject) => resolve(value))
}

MyPromise.reject = function (reason) {
    return new MyPromise((resolve,reject) => reject(reason))
}

Promise.all()

我们再回顾一下Promise.all()的使用吧

const p = new MyPromise()
p.all([p1,p2,......])

这其实就是传入很多个Promise(一个数组),等所有的Promise都fulfilled之后,返回新的Promise,于是基本上是下面这样

MyPromise.all = function (promiseList = []){
    const p = new MyPromise((resolve,reject) => {})
    return p
}

我们继续完善逻辑,我们需要存储传入数组中所有的返回结果,并且我们需要遍历这个数组,去看看每一个回调的执行情况,由于这边设计到异步,所以我们需要做一些操作,比如说使用计数器去实现异步的遍历记录

MyPromise.all = function (promiseList = []){
    const p = new MyPromise((resolve,reject) => {
        const result = [] // 用于存放所有的返回结果  
        const length = promiseList.length // 获取到数组的长度
        let resolvedCount = 0
        promiseList.forEach(p => {
            p.then(data => {
               result.push(data)
               resolvedCount++ // 注意!如果使用index也不行,index不是异步的
               if(resolvedCount === length){ // 到最后一个的时候
                   resolve(result)
               }
            }).catch(err => {
                    reject(err)
                }
            )
        })
    })
    return p
}

ok,我们的MyPromise.all()到这就完成了,我们接下来实现MyPromise.race()

Promise.race()

我们也回顾一下Promise.race()的使用吧,这其实和.all()很像

const p = new MyPromise()
p.race([p1,p2,......])

这其实也是传入很多个Promise(一个数组),只要有一个Promise是fulfilled,就返回新的Promise

MyPromise.race = function (promiseList = []){
    const p = new MyPromise((resolve,reject) => {})
    return p
}

我们继续完善逻辑,我们需要一个标记去记录是否已经有一个完成了,我们直接遍历数组并每次查看这个标记就ok了

MyPromise.race = function (promiseList = []){
    let resolved = false // 标记
    const p = new MyPromise((resolve,reject) => {
        promiseList.forEach(p => {
            p.then(data => {
                if(!resolved){
                    resolve(data)
                    resolved = true
                }
            }).catc((err) => {
                reject(err)
            })
        })
    })
    return p
}

好嘞,我们的MyPromise.race()到这就完成了!

我们来试试

我写了以下代码去测试.all()

    // 测试Promise.all
      setTimeout(() => {
        console.log("\n=== 开始测试Promise.all ===");
        const p3 = new MyPromise((resolve) =>
          setTimeout(() => {
            console.log("p3完成 - 1秒");
            resolve("p3结果");
          }, 1000)
        );
        const p4 = new MyPromise((resolve) =>
          setTimeout(() => {
            console.log("p4完成 - 2秒");
            resolve("p4结果");
          }, 2000)
        );
        const p5 = new MyPromise((resolve) =>
          setTimeout(() => {
            console.log("p5完成 - 3秒");
            resolve("p5结果");
          }, 3000)
        );
        console.log("Promise.all开始执行...");
        MyPromise.all([p3, p4, p5])
          .then((results) => console.log("Promise.all全部完成:", results))
          .catch((err) => console.log("Promise.all错误:", err));
      }, 1000);
      // 测试Promise.all失败情况
      setTimeout(() => {
        console.log("\n=== 开始测试Promise.all失败情况 ===");
        const p6 = new MyPromise((resolve) =>
          setTimeout(() => {
            console.log("p6完成 - 1秒");
            resolve("p6结果");
          }, 1000)
        );
        const p7 = new MyPromise((resolve, reject) =>
          setTimeout(() => {
            console.log("p7失败 - 500ms");
            reject("p7执行失败");
          }, 500)
        );
        const p8 = new MyPromise((resolve) =>
          setTimeout(() => {
            console.log("p8完成 - 3秒");
            resolve("p8结果");
          }, 3000)
        );
        console.log("Promise.all(失败情况)开始执行...");
        MyPromise.all([p6, p7, p8])
          .then((results) => console.log("Promise.all结果:", results))
          .catch((err) => console.log("Promise.all失败原因:", err));
      }, 5000);

这段代码输出以下结果

image.png

我们用以下代码去测试我们的.race()

      // 测试Promise.race
      setTimeout(() => {
        console.log("\n=== 开始测试Promise.race ===");
        const p9 = new MyPromise((resolve) =>
          setTimeout(() => {
            console.log("p9完成 - 3秒");
            resolve("p9结果");
          }, 3000)
        );

        const p10 = new MyPromise((resolve) =>
          setTimeout(() => {
            console.log("p10完成 - 1秒");
            resolve("p10结果");
          }, 1000)
        );

        const p11 = new MyPromise((resolve) =>
          setTimeout(() => {
            console.log("p11完成 - 2秒");
            resolve("p11结果");
          }, 2000)
        );

        console.log("Promise.race开始执行...");
        MyPromise.race([p9, p10, p11]).then((result) =>
          console.log("Race获胜者:", result)
        );
      }, 9000);

      // 测试Promise.race失败情况
      setTimeout(() => {
        console.log("\n=== 开始测试Promise.race失败情况 ===");
        const p12 = new MyPromise((resolve) =>
          setTimeout(() => {
            console.log("p12完成 - 2秒");
            resolve("p12结果");
          }, 2000)
        );

        const p13 = new MyPromise((resolve, reject) =>
          setTimeout(() => {
            console.log("p13失败 - 1秒");
            reject("p13执行失败");
          }, 1000)
        );

        const p14 = new MyPromise((resolve) =>
          setTimeout(() => {
            console.log("p14完成 - 3秒");
            resolve("p14结果");
          }, 3000)
        );

        console.log("Promise.race(失败情况)开始执行...");
        MyPromise.race([p12, p13, p14])
          .then((result) => console.log("Race获胜者:", result))
          .catch((err) => console.log("Race失败原因:", err));
      }, 13000);

输出的结果如下

image.png