JavaScript 是一门强有力的编程语言,在前端开发中是无可替代的。然而,它的异步特性给人们带来了一些挑战,特别是在处理多个并发异步任务时。ES2021 的新特性 Await Promise.all()
提供了一种简单、优雅且高效的方式来解决这个问题。
在这篇文章中,我们将深入探讨 Await Promise.all()
的用法和原理,并提供实际的示例以便读者更好地了解这种优秀的异步协程解决方案的结构、用途和潜在问题。
预备知识
在深入研究 Await Promise.all() 之前,我们应该先了解一些 JavaScript 异步编程的基本概念,例如:回调函数、Promise 和 async/await。如果你对这些概念还不熟悉,建议先阅读和理解相关知识。
Await Promise.all() 用法
ES2021 提供了一种名为 Promise.all()
的方法,它可以接收一个可迭代对象数组,并返回一个新的 Promise 对象,该对象会 resolve 一个包含所有输入 Promise 解析结果的数组。要想更好地说明这点,看下面的代码示例:
const promiseList = [promise1, promise2, promise3]; const resolvedList = await Promise.all(promiseList);
这个例子中,数组 promiseList
包含三个不同的 Promise 实例。Promise.all()
方法将这个数组作为参数传递,并将其封装在一个新的 Promise 对象中。解决新 Promise 对象将返回包含所有原始 Promise 实例解析结果的数组 resolvedList
。
在此过程中,所有的 Promise 实例都将开始并运行,但只有在所有 Promise 解析完成之后,新的包含所有解析结果的 Promise 才能被 resolve。如果定义的任何 Promise 之一 reject,Promise.all()
将立即 reject 并返回拒绝错误消息。
但是,如果你希望对 Promise 实例的重新顺序执行不那么感兴趣,而是想在 Promise 解析时立即处理单个 Promise 的解析结果,Promise.allSettled()
方法也许是个更好的选择,它返回的 Promise 并不会在 Promise 对象全部解析完成之后立即 resolve,而是在它们各自完成后返回 Promise 对象的正常终止值,不管其成功还是失败。
在这种情况下,可以使用 Promise.allSettled()
函数,例如:
const promiseList = [promise1, promise2, promise3]; const settledList = await Promise.allSettled(promiseList);
settledList
数组将包括所有 Promise 对象的执行结果,而不仅仅是成功的 Promise 对象。在这种情况下,返回的是一个对象数组,每个对象都具有如下三个属性之一:
status: "fulfilled"
成功时的状态,这个属性将会带有一个匹配值,指示原始 promise 的状态解析结果status: "rejected"
失败时的状态,这个属性将会带有一个异常对象,指示拒绝原始 promise 的对象value
VS.reason
一个带有错误代码或原因信息的对象,指示解析逻辑的输出结果
注意,Promise.allSettled()
方法是 ES2020 的新特性。如果你希望兼容早期的 JavaScript 引擎,你可能需要考虑使用强大但更兼容的库,例如 Async.js 或 Bluebird。
使用 Await Promise.all() 的实际示例
假设你正在开发一个 Web 应用程序,该应用程序需要从多个远程接口获取数据,然后将这些数据汇总到同一个组件中。这种类型的异步场景会导致代码的混乱、易错和低效。下面是一个基本示例:
const fetchDataOne = async () => { ... }; const fetchDataTwo = async () => { ... }; const fetchDataThree = async () => { ... }; const dataOne = await fetchDataOne(); const dataTwo = await fetchDataTwo(); const dataThree = await fetchDataThree(); const aggregateData = { dataOne, dataTwo, dataThree }; renderComponent(aggregateData);
在这个例子中,我们定义了三个异步函数 fetchDataOne()、fetchDataTwo() 和 fetchDataThree(),它们会发起远程调用相应的 API 并返回解析的数据。接下来,我们按顺序调用这些函数,并通过 await 关键字等待 Promise 对象完成。最后,我们将所有的数据合并到一个单独的对象中,并传递给渲染组件的函数。
使用 await 关键字等待 Promise 对象返回结果是一个正确而经常使用的模式,但是这种方法的缺点是它需要将同步函数改写为异步函数,并且会导致所有异步函数按顺序执行,不管它们之间是否有相关性。
现在,我们将使用 Promise.all()
和 Await
原语来重新编写这个场景,以提高代码的运行效率:
-- -------------------- ---- ------- ----- ------------ - ----- -- -- - --- -- ----- ------------ - ----- -- -- - --- -- ----- -------------- - ----- -- -- - --- -- ----- --------- -------- ---------- - ----- ------------- --------------- --------------- ----------------- --- ----- ------------- - - -------- -------- --------- -- -------------------------------
在这个新版本中,我们仍然定义了三个异步函数 fetchDataOne()、fetchDataTwo() 和 fetchDataThree(),但我们不再按照顺序调用它们。相反,我们通过 Promise.all()
的方式将这些函数打包在一个数组中,同时显式地等待所有 Promise 的结果,而非一个接一个的等待。这个过程将导致并发执行,因此我们可以获得更快的响应时间和更好的性能。在所有 Promise 全部解析之后,我们将所有数据合并到一个对象中,并传递给渲染组件的函数。
需要注意的是,在使用 Promise.all()
时,应该谨慎考虑 API 响应时间、资源使用情况和方案适用情况等因素,以确保良好的性能,并减少良性抖动的可能性。
结论
对于那些在开发中需要处理多个异步任务的前端工程师而言,借助 ES2021 新特性Await Promise.all()
,使得我们可以简化代码,提高程序性能。 在本文中,我们讨论了Promise.all()
方法的工作原理及其在处理并发异步事件时的优势,提供了实际的示例来说明如何使用 Await-and-Promise.all()
对异步 JavaScript 代码进行优化,这将使您写出更高效、更简单和维护性更佳的代码。
还有更多的 JavaScript 的异步编程方法和工具库,如 async.js, Bluebird,而新的语法支持模块也可以用于优化Web应用的性能,欢迎读者继续探索和研究。
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/674fe387fbd23cf89070b315