
core-js 中的 Await dictionary 提案Promise.allKeyed 与 Promise.allSettledKeyed 完全指南【免费下载链接】core-jsStandard Library项目地址: https://gitcode.com/GitHub_Trending/co/core-js导读Await dictionary 是 TC39 正在推进的 JavaScript 提案proposal-await-dictionary其核心目标是为开发者提供一种“按对象键名组织 Promise、统一等待结果”的并发原语Promise.allKeyed与Promise.allSettledKeyed。本文以 docs/web/docs/features/proposals/await-dictionary.md 为骨架结合 core-js 仓库中的模块源码与 QUnit 测试用例系统讲解这两个方法的类型签名、语义细节、安装入口、使用示例与底层实现原理帮助你直接在当前项目中使用这一提案能力。提案背景为什么需要 Keyed 并发方法在现有标准 API 中Promise.all接受一个可迭代对象通常是数组结果也以数组形式返回。当并发任务的来源是一组带名字的配置项、命名资源或字典结构时开发者不得不在“数组 手动映射回键名”之间来回转换既啰嗦又容易在索引上出错。Await dictionary 提案的出发点是允许你直接传入一个普通对象字典键名即结果键名。Promise.allKeyed在语义上相当于Object.fromEntries与Promise.all的组合而Promise.allSettledKeyed则是“keyed 版”的Promise.allSettled即使个别 Promise 失败也会收集所有键的最终状态而不会整体拒绝。从源码注释可以看到core-js 正是依据该提案实现这两个方法的见 esnext.promise.all-keyed.js 与 esnext.promise.all-settled-keyed.js 中的注释// Promise.allKeyed method/// Promise.allSettledKeyed method均标注提案地址https://github.com/tc39/proposal-await-dictionary。模块与内置方法签名原文档明确了该提案在 core-js 中由两个模块承载模块文件相对仓库根目录提供的方法esnext.promise.all-keyed.jsPromise.allKeyedesnext.promise.all-settled-keyed.jsPromise.allSettledKeyed对应到原生内置对象的 TypeScript 签名如下继承自原文档class Promise { allKeyedT extends Recordstring, unknown( obj: T ): Promise{ [K in keyof T]: AwaitedT[K] }; allSettledKeyedT extends Recordstring, unknown( obj: T ): Promise{ [K in keyof T]: PromiseSettledResultAwaitedT[K] }; }需要说明的语义要点allKeyed返回的 Promise 在所有键对应的值全部 resolve 后兑现只要有一个值 reject整个结果就会以该错误 reject与Promise.all的“快速失败”行为一致。allSettledKeyed永不因单个值 reject 而整体拒绝而是为每个键生成{ status: fulfilled, value }或{ status: rejected, reason }形式的PromiseSettledResult与Promise.allSettled行为一致。两者都接受普通值非 Promise 值会被直接当作已兑现处理这一点在测试 esnext.promise.all-keyed.js 中有明确验证。使用示例以下是原文档给出的标准示例直接展示了“字典输入、字典输出”的用法await Promise.allKeyed({ a: Promise.resolve(1), b: Promise.resolve(2), c: 3, }); // { a: 1, b: 2, c: 3 } await Promise.allSettledKeyed({ a: Promise.resolve(1), b: Promise.reject(2), c: 3, }); // { a: { status: fulfilled, value: 1 }, b: { status: rejected, reason: 2 }, c: { status: fulfilled, value: 3 } }典型场景带名字的并发请求假设需要同时请求三个具名资源并保持结构对应const result await Promise.allKeyed({ user: fetch(/api/user).then(r r.json()), posts: fetch(/api/posts).then(r r.json()), settings: fetch(/api/settings).then(r r.json()), }); // result.user / result.posts / result.settings 一一对应无需再手动 zip相比Promise.all返回数组后再按索引取值allKeyed让每个异步结果天然拥有语义化键名代码可读性与可维护性都更好。安装与使用入口原文档给出了三种入口方式Entry pointscore-js/proposals/await-dictionary core-js(-pure)/actual|full/promise/all-keyed core-js(-pure)/actual|full/promise/all-settled-keyed它们的实际对应关系与使用姿势如下。1. 提案聚合入口一次引入两个方法仓库中的 packages/core-js/proposals/await-dictionary.js 是一个聚合模块内部仅做两件事require(../modules/esnext.promise.all-keyed); require(../modules/esnext.promise.all-settled-keyed);因此你只需一次性引入即可同时获得两个方法import core-js/proposals/await-dictionary; // 或 CommonJS require(core-js/proposals/await-dictionary); await Promise.allKeyed({ a: Promise.resolve(1) }); await Promise.allSettledKeyed({ a: Promise.resolve(1) });2. 单一方法入口按需加载若只想引入其中一个方法可以使用精确到方法的入口以 actual/full 版本为例文件位于 packages/core-js/actual/promise/all-keyed.js 与 packages/core-js/actual/promise/all-settled-keyed.jsimport core-js/actual/promise/all-keyed; import core-js/actual/promise/all-settled-keyed; // 或 require(core-js/actual/promise/all-keyed); require(core-js/actual/promise/all-settled-keyed);full/与actual/的区别在于actual入口只包含按提案最新状态可用的实现full则包含 core-js 的全部特性集。core-js-pure版本不污染全局原型同样支持这两个入口只是引入前缀为core-js-pure/。关于入口点的完整说明可参考 docs/web/docs/usage.md 中 “Entry points” 一节的约定。// core-js-pure 版本示例 const { allKeyed } require(core-js-pure/actual/promise/all-keyed);源码级实现原理allKeyed 的核心流程esnext.promise.all-keyed.js 的实现要点如下通过newPromiseCapabilityModule.f(C)创建 Promise 能力capabilitythis指向调用时的构造函数保证子类化语义。通过Reflect.ownKeys拿到输入对象的全部自有键含 Symbol 键再用getOwnPropertyDescriptor过滤出可枚举enumerable自有属性——这一点与Object.keys的语义保持一致。对每个可枚举键调用C.resolve(promises[key])统一包装为 Promise普通值也会被 resolve随后.then注册兑现回调。使用remaining计数器跟踪未完成数量全部完成后用create(null)构造一个null 原型的结果对象并通过createProperty按原键名回填结果最终resolve(res)。任意一个值 reject 时直接调用reject整体失败。allSettledKeyed 的差异esnext.promise.all-settled-keyed.js 与allKeyed结构几乎一致唯一区别在于第 33-45 行的createElementResolver辅助函数它对每个值同时注册fulfilled与rejected两条回调路径无论结果如何都会把{ status: fulfilled, value }或{ status: rejected, reason }写入对应位置因此整体永远不会因单个值的失败而拒绝。关键行为总结均有测试佐证仓库中的单元测试tests/unit-global/esnext.promise.all-keyed.js 与 tests/unit-global/esnext.promise.all-settled-keyed.js对以下行为做了完整覆盖行为说明测试位置支持原始值非 Promise 值直接按已兑现处理两个测试文件的 resolved with primitives 用例空对象传入{}立即兑现为空对象resolved with empty object 用例忽略不可枚举与原型属性只处理输入对象自身的可枚举键原型链上的键被忽略resolved with hidden attributes 用例Symbol 键支持结果对象保留 Symbol 键symbol keys 用例结果顺序稳定即使 Promise 以不同顺序完成结果键顺序仍与输入一致依赖索引槽位机制keys order 用例结果对象 null 原型Object.getPrototypeOf(result) nullresult object has null prototype 用例子类化支持allKeyed.call(SubPromise, ...)返回SubPromise实例subclassing 用例非法输入拒绝传入字符串等非对象会以TypeError拒绝rejected on incorrect input 用例以“隐藏属性”用例为例输入对象Object.create({ proto: Promise.resolve(hidden) })且含一个enumerable: false的invisible键时结果只包含{ visible: 42 }证明实现严格遵循“仅可枚举自有键”的语义。延迟兑现下的键序保持由于allKeyed在遍历时用keys[index] key和values[index] undefined预先占位再在回调中按index回填因此即便较慢的 Promise 最后完成结果对象的键顺序依然等于输入对象的键顺序。测试 keys order 专门构造了b延迟 10ms 兑现的场景来验证这一点。与 Promise.all / allSettled 的对比特性Promise.allPromise.allKeyedPromise.allSettledPromise.allSettledKeyed输入形态可迭代对象数组等对象字典可迭代对象对象字典输出形态数组按原键名组织的对象PromiseSettledResult[]数组按原键名组织的PromiseSettledResult对象快速失败是是否汇总所有状态否汇总所有状态键名语义无索引定位有语义化定位无有如果你的并发任务天然以“命名资源”形式存在配置加载、具名请求、分组校验等keyed 系列方法能显著减少“数组 ↔ 字典”之间的人工映射代码。注意事项与版本现状该能力目前属于esnext提案阶段特性对应模块文件均以esnext.前缀命名尚未进入标准库依赖原生Promise.allKeyed的代码在绝大多数运行时中不可用必须通过 core-js 或 core-js-pure 引入。引入后是向Promise构造函数添加静态方法位于 packages/core-js/modules/esnext.promise.all-keyed.js 的$({ target: Promise, stat: true }, ...)中stat: true表示挂载为静态方法而非原型方法。在core-js-pure不污染全局场景下方法通过 packages/core-js/actual/promise/all-keyed.js 中的包装函数导出调用时若this可调用则作为构造上下文传入否则回退到原生Promise。由于提案仍在演进具体语义如是否处理 Symbol 键、结果对象原型等以当前 core-js 版本实现与 TC39 提案最新文本为准。小结Await dictionary 提案为 JavaScript 并发编程补上了一块实用拼图Promise.allKeyed让你用字典组织并发任务并保持键名语义Promise.allSettledKeyed则提供“全量汇总、永不整体失败”的 keyed 版 allSettled。通过 packages/core-js/proposals/await-dictionary.js 或两个独立入口即可在当前项目中启用其内部实现与测试用例esnext.promise.all-keyed.js、esnext.promise.all-settled-keyed.js为理解语义边界可枚举自有键、Symbol 键、null 原型、键序稳定、子类化提供了完整的可验证依据值得在涉及命名并发任务的场景中优先采用。【免费下载链接】core-jsStandard Library项目地址: https://gitcode.com/GitHub_Trending/co/core-js创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考