在 Web 前端开发中,异步编程方式已经成为了日常开发中的必备技能。Promise 是实现异步编程最常用的一种方式。ES6 引入了 Promise,ES10 对其进行了增强,新添加了 Promise.allSettled() 方法。而在 ES11 中,Promise.any() 方法被正式加入到了 Promise API 中,它解决了 Promise.race() 的一些弊端,让异步编程更加强大和灵活。
Promise.race() 的问题
Promise.race() 方法可以接收一组 Promise 实例,只要其中有一个 Promise 对象状态发生改变(不管是 resolve 还是 reject),最终返回的 Promise 对象的状态就会跟着改变。有利有弊,这种方式是非常高效和强大的,但是它有一个缺陷,就是仅仅返回最先被解决的 Promise 对象的结果,而忽略了其他未被解决的 Promise 实例的信息。
例如,下面的代码中同时发起两个请求,其中一个请求成功,另一个请求失败:
// javascriptcn.com 代码示例 const promise1 = new Promise((resolve, reject) => { setTimeout(() => { resolve('Promise 1 resolved'); }, 3000); }); const promise2 = new Promise((resolve, reject) => { setTimeout(() => { reject('Promise 2 rejected'); }, 2000); }); Promise.race([promise1, promise2]) .then(value => console.log(value)) .catch(error => console.log(error));
运行上述代码,我们发现控制台输出的信息只有 "Promise 1 resolved",没有任何关于 Promise 2 的信息。这是因为 Promise.race() 方法只关心第一个被解决的 Promise 对象。如果我们希望同时拿到多个 Promise 实例的结果,Promise.race() 就无法帮忙了。
Promise.any() 方法的优势
Promise.any() 方法在解决 Promise.race() 的问题上,提供了更加灵活和全面的解决方案。Promise.any() 方法同样接收一组 Promise 实例,但是只有当所有的 Promise 全部 reject 才会返回 reject,而如果其中任一 Promise resolve,则会返回 resolve。
下面是同样的两个 Promise 实例,但是这次使用 Promise.any():
Promise.any([promise1, promise2]) .then(value => console.log(value)) .catch(error => console.log(error));
在这个例子中,由于 Promise 1 在 Promise 2 之前解决,故返回 "Promise 1 resolved" 的信息。
另外,如果所有 Promise 实例均 reject,会返回 AggregateError 对象。我们可以通过捕获此错误对象并打印其错误信息,从而确保全部错误信息被捕获。
下面的例子同时发起两个请求,其中一个请求成功,另一个请求失败:
// javascriptcn.com 代码示例 const promise1 = new Promise((resolve, reject) => { setTimeout(() => { resolve('Promise 1 resolved'); }, 3000); }); const promise2 = new Promise((resolve, reject) => { setTimeout(() => { reject('Promise 2 rejected'); }, 2000); }); Promise.any([promise1, promise2]) .then(value => console.log(value)) .catch(errors => console.error(errors));
控制台输出的信息是:
Promise 1 resolved
由于 Promise 1 最先被解决,所以最终返回的是 Promise 1 的 resolve 的信息。
而如果我们将 Promise 2 的时间延长到 4000 ms,那么控制台输出的信息是:
AggregateError: All promises were rejected at Promise.any at resolveAggregateError (index.js:6) at index.js:9 (anonymous) @ index.js:11
这是因为在延长时间后,两个 Promise 都被 reject 了,所以最终返回的是一个 AggregateError 对象,打印了所有的错误信息。
如何使用 Promise.any()
Promise.any() 对于简化异步编程和提高代码可读性都是非常有帮助的。我们可以通过下面的代码进行简单的实验:
const promises = [ fetch("https://api.github.com/users/nickjian2009"), fetch("https://api.github.com/users/NoSuchUserExists") ]; Promise.any(promises) .then(res => console.log(res)) .catch(err => console.error(err));
在浏览器环境下,我们通过 fetch 方法构造两个请求,一个是有效的请求,一个是非法的请求。使用 Promise.any() 方法进行解决的结果是:
{login: "nickjian2009", ...}
由于第一个请求是有效的,所以成功返回结果。
在 Node.js 环境下我们通过下面的代码进行测试:
const promises = [ readFile("filePath1/unexisted-file.txt"), readFile("filePath2/sample.txt") ]; Promise.any(promises) .then(res => console.log(res)) .catch(err => console.error(err));
在 Node.js 环境下读取两个文件,一个是不存在的文件,一个存在的文件。使用 Promise.any() 方法进行解决的结果是:
<Arraybuffer>
由于第二个文件存在,成功返回文件二的内容。
总结
Promise 一直是异步编程的最重要工具之一,ES11 引入的 Promise.any() 方法解决了 Promise.race() 的一些问题,提供了更加全面和灵活的异步编程解决方案。开发者可以充分利用这个方法来编写更加健壮和可读性更好的代码。
来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/65392a2c7d4982a6eb26e6b2