随手刷题——05.实现一个简单的Promise.race

233 阅读3分钟

定义

Promise.race()的功能,它接受一个Promise实例数组作为参数并返回一个Promise,它将与第一个传递的promise相同的完成方式被完成。它可以是完成(fulfilled),也可以是失败(rejected),这要取决于第一个完成的方式是两个中的哪个。

如果传的迭代是空的,则返回的promise将永远是pending状态。

如果迭代包含一个或多个非Promise类型的值和/或已改变状态的Promise,则Promise.race将解析为迭代中找到的第一个值。

初步实现

根据以上定义,对于每个 Promise 对象,通过 then() 方法监听其成功和失败状态,如果当前 race 操作还没有完成,则将 completed 标记为已完成,并通过 resolve()reject() 方法返回当前 Promise 的结果或错误信息。如果当前 race 操作已经完成,则忽略当前 Promise 对象。

image.png

一些边界处理

  1. 数组为空。在实现 promiseRace() 函数的时候,我们应该首先检查传入的 Promise 数组是否为空。按照MDN的规则,如果是空数组,则返回的promise将永远是pending状态。但是在实际开发中,返回rejected状态应该更为合理。

image.png

  1. Promise 数组中存在非 Promise 对象。在传入的 Promise 数组中,可能存在非 Promise 对象,此时 Promise.race() 方法会返回一个 "TypeError" 类型的 Promise 对象。为了避免该情况的发生,我们可以在遍历 Promise 数组的时候,使用 Promise.resolve() 包装非 Promise 对象,将其转换为 Promise 对象。

  2. Promise 数组中存在已完成的 Promise 对象。在使用 Promise.race() 方法时,如果传入的 Promise 数组中有一个或多个已完成的 Promise 对象,则 Promise.race() 方法会立即返回第一个完成的 Promise 对象的结果。但是在我们自己实现的 promiseRace() 函数中,我们需要手动检查每个 Promise 对象的状态,以便及时的 resolve 或 reject。

image.png

测试用例

我们可以使用以下的测试用例对代码进行测试。首先,创建三个 Promise 对象,分别是 promise1promise2promise3。其中,promise1 在 3 秒钟后会被 resolve,promise2 在 2 秒钟后会被 reject,而 promise3 在 1 秒钟后会被 resolve。

然后我们使用 Promise.race() 方法传入这三个 Promise 对象,并在它的返回结果上调用 then() 方法和 catch() 方法。由于 promise3 最先被 resolve,因此 Promise.race() 方法会立即返回它的结果,即字符串 "Promise 3 resolved"。并且,由于返回的是 resolve 的结果,因此 catch() 方法不会被触发。

image.png

总结

当我们在面试的时候遇到这种手写代码的题目是,可以优先写出代码的主要逻辑,完成之后再开始补充边界处理。这样可以让我们在写的时候保持清晰的思路。Promise.race与之前的Promise.all一样,都是面试时会遇到的高频手写题,我后面继续更新随手刷题系列的,也欢迎各位在评论区讨论~