Promise.all([p1, p2]) 只能靠索引拿结果,这事儿忍了十年——Firefox 155 今天把它彻底原生化了
用过 Promise.all 的都知道,结果是个数组,顺序和你传入的顺序严格对应。
想象一个常见的真实场景:你同时请求用户信息、订单列表、商品推荐三个接口,写出来是这样的:
const [user, orders, items] = await Promise.all([
fetchUser(),
fetchOrders(),
fetchItems()
]);
看起来没问题。但三个月后你重构这段代码,加了一个接口、调了顺序,忘记同步改解构赋值——程序不会报错,user 拿到的是 orders 的数据,orders 拿到的是 items 的。线上开始出现莫名其妙的用户信息错乱。
这个坑在团队代码库里存在了十年,因为 Promise.all 本身从来不告诉你哪个位置对应哪个 promise。
Firefox 155 稳定版今天把这个彻底翻了。
新增的 Promise.allKeyed() 和 Promise.allSettledKeyed(),接受一个对象而不是数组:
const { user, orders, items } = await Promise.allKeyed({
user: fetchUser(),
orders: fetchOrders(),
items: fetchItems()
});
// user 就是用户信息,orders 就是订单,items 就是商品推荐
// 顺序怎么调,结果都能对应上
Promise.allSettledKeyed() 同理,但返回结构是 { status: 'fulfilled'|'rejected', value|reason }:
const results = await Promise.allSettledKeyed({
user: fetchUser(),
orders: fetchOrders(),
items: fetchItems()
});
// 哪个失败了,一目了然
for (const [key, result] of Object.entries(results)) {
if (result.status === 'rejected') {
console.error(`${key} failed:`, result.reason);
}
}
为什么说它是彻底原生化而不是简单封装?
这是 TC39「await dictionary」提案的标准实现,Firefox 155 是第一个稳定支持的浏览器。你不需要任何 polyfill,不需要任何库,结果靠名字拿而不是靠索引猜——这才是 Promise 组合子该有的样子。
Safari 还没跟上来,但 Firefox 155 已经稳定了这两个方法,Chrome 预计下个版本也会支持。
下一步怎么做?
如果你现在有类似 Promise.all([p1, p2, p3]) 的代码,先数一数数组里每个 promise 是什么,然后:
- 打开 Firefox 155,检查是否支持
Promise.allKeyed - 把数组改成对象字面量,key 就是你想叫的名字
- 把解构改成对象属性访问
results.user而不是results[0]
这不只是一个写法上的便利——它把运行时才会暴露的顺序 bug,提前到写代码的时候就能发现。
评论区
0 条评论
登录后可评论。