你以为 Promise.all 的结果只能靠索引拿?今天这个新语法把它彻底翻了
写过前端的都踩过这个坑——并发发三个请求,结果用数组索引解构拿值,调一下顺序整个页面的数据全乱了。
这个问题在 Promise.all 诞生的第一天就存在。数组索引是位置依赖的,一旦你重构时调换了 promise 的顺序,或者中间插了一个新的 promise,所有依赖索引的地方都要跟着改。这种 bug 往往在上线之后才暴露,而且很难追踪。
Promise.allKeyed() 就是来解决这个问题的。
Firefox 155(2026-09-01 稳定版)首发了这个 TC39 提案的原生支持。语法很直接——你把 promise 打包成一个对象,而不是数组:
// 旧写法:位置依赖
const [shape, color, mass] = await Promise.all([
getShape(),
getColor(),
getMass(),
]);
// 新写法:命名对应
const { shape, color, mass } = await Promise.allKeyed({
shape: getShape(),
color: getColor(),
mass: getMass(),
});
结果直接用键名解构,调换顺序、增删字段都不影响。这是真正的重构安全。
Promise.allSettledKeyed() 对应 Promise.allSettled 的语义,返回一个键名到状态对象的映射:
const results = await Promise.allSettledKeyed({
user: fetchUser(),
posts: fetchPosts(),
});
if (results.user.status === "fulfilled") {
console.log(results.user.value);
} else {
console.error(results.user.reason);
}
每个字段独立追踪成功/失败,不会因为一个 rejection 导致其他结果丢失。
还有一个隐性价值:旧写法里,如果 await getShape() 抛出异常,getColor() 和 getMass() 的 promise 仍然在跑,但没有任何 handler 接住——这会产生 unhandled rejection,在某些环境下会导致进程退出。Promise.allKeyed 的实现保证了所有 promise 都被正确管理。
兼容性方面: Firefox 155 首发,Chrome 和 Safari 还未支持。Stage 2.7 意味着 API 设计已经冻结,后续主要是实现和反馈收集。如果现在想用,core-js 有 polyfill:
import "core-js/proposals/promise-all-keyed";
或者用 JSR 上的 @std/async:
import { allKeyed } from "@lowlighter/std-async";
const { user, posts } = await allKeyed({ /* ... */ });
下一步:如果你的项目里有超过三个并发 fetch 的场景,现在就可以考虑引入 polyfill 统一改造。新写的代码用对象解构替代数组索引,既是代码可读性升级,也是对即将到来的原生支持提前做准备。
评论区
登录后可评论。