能否摆脱Promise.all对数组索引的依赖?改用对象解构实现
问题描述
我目前通过Promise.all并行处理三个异步方法,用数组解构获取结果,代码如下:
const [ page, hierarchies, courses, ] = await Promise.all([ usePage('home'), useHierarchies('course'), useCoursesByConfigKeys(['firstCourses', 'secondCourses']) ])
但存在明显隐患:如果不慎修改Promise.all中数组的顺序,却未同步调整解构变量的顺序,就会触发运行时错误,例如:
const [ page, hierarchies, courses, ] = await Promise.all([ useHierarchies('course'), useCoursesByConfigKeys(['firstCourses', 'secondCourses']), usePage('home'), ])
我想改用对象解构的方式避免这个问题,类似以下写法,但不确定是否可行:
const { page, hierarchies, courses, } = await Promise.all({ hierarchies: useHierarchies('course'), courses: useCoursesByConfigKeys(['firstCourses', 'secondCourses']), page: usePage('home'), })
解决方案
首先明确:Promise.all仅接受可迭代对象(如数组)作为参数,直接传入对象会报错,因为对象不属于可迭代类型。不过我们可以通过简单的转换技巧,实现基于对象的并行异步处理,从而用对象解构彻底规避顺序依赖问题。
方法1:封装对象版并行处理工具函数
自己实现一个工具函数,接收包含Promise的对象,返回一个解析为对应结果对象的Promise:
async function promiseAllObject(obj) { const entries = Object.entries(obj); const resolvedEntries = await Promise.all( entries.map(async ([key, promise]) => [key, await promise]) ); return Object.fromEntries(resolvedEntries); }
之后就能按你期望的方式使用:
const { page, hierarchies, courses } = await promiseAllObject({ page: usePage('home'), hierarchies: useHierarchies('course'), courses: useCoursesByConfigKeys(['firstCourses', 'secondCourses']) });
这种方式下,对象属性的顺序不影响解构结果,变量与异步操作通过键名绑定,不会因顺序修改出错。
方法2:直接用Promise.all结合对象转换(无需封装函数)
如果不想单独封装工具函数,也可以在业务代码中直接处理:
const promiseObj = { page: usePage('home'), hierarchies: useHierarchies('course'), courses: useCoursesByConfigKeys(['firstCourses', 'secondCourses']) }; const resolvedEntries = await Promise.all( Object.entries(promiseObj).map(([key, p]) => p.then(res => [key, res])) ); const { page, hierarchies, courses } = Object.fromEntries(resolvedEntries);
原理与工具函数一致:先将对象转为键值对数组,并行处理所有Promise后,再将结果转回对象。
注意事项
- 和原生
Promise.all逻辑一致,只要有一个Promise被拒绝,整个处理会立即抛出错误;如果需要容错,可以将Promise.all替换为Promise.allSettled,再自行处理成功/失败的结果。 - 两种方式都彻底解决了顺序依赖问题,从根源上避免了因顺序修改导致的运行时错误。
内容的提问来源于stack exchange,提问作者Ali EXE
相关产品推荐
相关产品推荐

