定义
Promise.race()的功能,它接受一个Promise实例数组作为参数并返回一个Promise,它将与第一个传递的promise相同的完成方式被完成。它可以是完成(fulfilled),也可以是失败(rejected),这要取决于第一个完成的方式是两个中的哪个。
如果传的迭代是空的,则返回的promise将永远是pending状态。
如果迭代包含一个或多个非Promise类型的值和/或已改变状态的Promise,则Promise.race将解析为迭代中找到的第一个值。
初步实现
根据以上定义,对于每个 Promise 对象,通过 then() 方法监听其成功和失败状态,如果当前 race 操作还没有完成,则将 completed 标记为已完成,并通过 resolve() 或 reject() 方法返回当前 Promise 的结果或错误信息。如果当前 race 操作已经完成,则忽略当前 Promise 对象。
一些边界处理
- 数组为空。在实现
promiseRace()函数的时候,我们应该首先检查传入的 Promise 数组是否为空。按照MDN的规则,如果是空数组,则返回的promise将永远是pending状态。但是在实际开发中,返回rejected状态应该更为合理。
-
Promise 数组中存在非 Promise 对象。在传入的 Promise 数组中,可能存在非 Promise 对象,此时
Promise.race()方法会返回一个 "TypeError" 类型的 Promise 对象。为了避免该情况的发生,我们可以在遍历 Promise 数组的时候,使用Promise.resolve()包装非 Promise 对象,将其转换为 Promise 对象。 -
Promise 数组中存在已完成的 Promise 对象。在使用
Promise.race()方法时,如果传入的 Promise 数组中有一个或多个已完成的 Promise 对象,则Promise.race()方法会立即返回第一个完成的 Promise 对象的结果。但是在我们自己实现的promiseRace()函数中,我们需要手动检查每个 Promise 对象的状态,以便及时的 resolve 或 reject。
测试用例
我们可以使用以下的测试用例对代码进行测试。首先,创建三个 Promise 对象,分别是 promise1、promise2 和 promise3。其中,promise1 在 3 秒钟后会被 resolve,promise2 在 2 秒钟后会被 reject,而 promise3 在 1 秒钟后会被 resolve。
然后我们使用 Promise.race() 方法传入这三个 Promise 对象,并在它的返回结果上调用 then() 方法和 catch() 方法。由于 promise3 最先被 resolve,因此 Promise.race() 方法会立即返回它的结果,即字符串 "Promise 3 resolved"。并且,由于返回的是 resolve 的结果,因此 catch() 方法不会被触发。
总结
当我们在面试的时候遇到这种手写代码的题目是,可以优先写出代码的主要逻辑,完成之后再开始补充边界处理。这样可以让我们在写的时候保持清晰的思路。Promise.race与之前的Promise.all一样,都是面试时会遇到的高频手写题,我后面继续更新随手刷题系列的,也欢迎各位在评论区讨论~