Await Dictionary S3
中文标题:Await 字典
- 阶段: Stage 3
- 状态: 进行中
- ECMAScript 版本: —
- 同步时间: 2026年11月3日
- English original · 官方仓库
该提案解决的是等待多个具名异步值时,每个 await 串行执行或依赖 Promise.all 按位置返回结果的问题。它引入 Promise.allKeyed,接收一个 Promise 对象并返回一个 Promise,其结果对象的键对应已等待的值。它还新增 Promise.allSettledKeyed,用于按键返回 settled 结果,并遵循 joint iteration 提案的结构。
以下 README 来自上游仓库,其中的阶段或状态标注可能滞后;当前信息以提案概览为准。
Promise 的 Await 字典
状态
阶段:3
提案推进人:
- Ashley Claymore (@acutmore)
- Jordan Harband (@ljharb)
- Chris de Almeida (@ctcpip)
- 待定:Rick Waldron (@rwaldron)
作者:
- Alexander J. Vincent (@ajvincent)
- Ashley Claymore (@acutmore)
动机
对各个属性分别使用 await 会形成瀑布式流程,而不是并行运行请求:
Promise.all 有所帮助,但它基于顺序而非名称,这可能导致混淆:
使用现有语法的解决方案可能很冗长,并且会 污染 作用域中的变量数量:
此外,上述模式有产生未处理 Promise 拒绝的风险。如果 await shapeRequest 抛出异常,那么 colorRequest 或 massRequest 这两个 Promise 没有附加任何处理器——如果其中任一 Promise 拒绝,就会导致未处理的 Promise 拒绝错误。在某些系统上,这会导致进程退出。
提议的解决方案
这有意地遵循 https://github.com/tc39/proposal-joint-iteration 的结构。
正如 Promise.all 之于 Iterator.zip
Promise.allKeyed 之于 Iterator.zipKeyed
附加 API
该提案还将此功能扩展到 Promise.allSettled 的使用者。
现有解决方案
实现
Polyfill/转译器实现
- core-js:为
Promise.allKeyed和Promise.allSettledKeyed提供 polyfill。 - es-shims:为
Promise.allKeyed和Promise.allSettledKeyed提供 polyfill。
原生实现
无。
问答
为什么不提供深拷贝选项?
抛开 JSON.stringify 不谈,JavaScript 内置 API 深度遍历任意对象并不常见。
Array.prototype.flat 是 深层 的,但仅限数组定义明确的边界。
为什么只处理自有键?
这遵循了 Object.keys 等其他内置方法,也与 https://github.com/tc39/proposal-joint-iteration 一致。
那符号键呢?
所有可枚举属性都会被使用,包括可枚举符号。
这与 https://github.com/tc39/proposal-joint-iteration 一致。
这确实不同于现有解决方案,后者遵循 Object.keys 语义(忽略符号)。由于自有可枚举符号的使用率很低,这一差异不被认为是个问题。
考虑过的替代方案
Promise.ownProperties
Promise.fromEntries
Promise.all 重载
根据参数是否可迭代进行分派。
"这 会 避免向 API 表面引入新名称。然而,输出形态取决于输入形态这一点令人不适,而且存在意外传入多个参数而不是数组的风险。例如:
虽然目前由于 p1 不可迭代,这会抛出异常,但该重载会开始允许这种调用,却不会执行调用者意图的操作。
专用语法
受 Swift 等其他语言启发——参见:https://docs.swift.org/swift-book/documentation/the-swift-programming-language/concurrency#Calling-Asynchronous-Functions-in-Parallel
在 await <exp> 中对 async const 标识符的所有引用都会被隐式等待。
上面的代码(大致)等价于: