有没有兼具Promise.all性能与简洁性的多资源加载替代方案?
兼顾易用性与并行性能的解决方案
你可以通过先批量发起所有异步请求,再映射结果到对象的方式,同时保留第二种写法的清晰结构和第一种写法的并行性能:
基础实现
interface MyImages { apple: HTMLImageElement, banana: HTMLImageElement, carrot: HTMLImageElement } async function fetchImages(): Promise<MyImages> { // 一次性创建所有加载Promise,此时所有图片请求已并行发起 const imagePromises = { apple: asyncImageLoad("/images/apple.png"), banana: asyncImageLoad("/images/banana.png"), carrot: asyncImageLoad("/images/carrot.png") }; // 等待对应Promise完成,直接赋值到对象属性 return { apple: await imagePromises.apple, banana: await imagePromises.banana, carrot: await imagePromises.carrot }; }
通用工具函数实现(更简洁)
如果需要处理大量键值对,可以封装一个通用工具函数,避免重复代码:
// 通用函数:解析对象中所有的Promise,返回结构一致的结果对象 async function resolveAllPromises<T extends Record<string, Promise<any>>>(obj: T): Promise<{[K in keyof T]: Awaited<T[K]>}> { const resolvedEntries = await Promise.all( Object.entries(obj).map(async ([key, promise]) => [key, await promise]) ); return Object.fromEntries(resolvedEntries) as {[K in keyof T]: Awaited<T[K]>}; } // 使用方式 async function fetchImages(): Promise<MyImages> { return resolveAllPromises({ apple: asyncImageLoad("/images/apple.png"), banana: asyncImageLoad("/images/banana.png"), carrot: asyncImageLoad("/images/carrot.png") }); }
原理说明
Promise的异步操作在创建时就会立即执行,所以先定义所有imagePromises的那一刻,所有图片请求已经同时发送出去了。后续的await只是等待各自的Promise完成,不会阻塞其他请求的执行,完美兼顾了代码的可读性和并行加载的性能。
内容的提问来源于stack exchange,提问作者Ryan Peschel
相关产品推荐
相关产品推荐

