存储异步Promise后无法访问已解析值的技术问题
问题描述
我尝试把未决Promise作为对象的值存储,等待其解析后再调用,步骤如下:
let names = ["aaron", "bob", "john", "aaron"]; let allNames = {};
// 以名称为键初始化对象
names.forEach(name => { if (!allNames[name]) { allNames[name] = null; } });
// 并行执行异步请求,将未决Promise存储为对象值
let allDataForNamedPerson; for (const [x] of names) { if (!allNames[name]) { allDataForNamesPerson = this.getNameData(name)// 异步API调用 allNames[name] = allDataForNamesPerson // 存储Promise } }
随后等待所有Promise解析:
await Promise.all([...Object.values(this.allNames)]);
问题是,当我从对象中查找已解析的值(例如allNames["john"])时,控制台显示该值是一个包裹着对象的Promise:
promise { salary: 41992, position: clerk }
因此无法通过allNames["john"].salary访问属性,返回undefined。请问我哪里出错了?
问题分析与解决
错误1:循环变量处理逻辑错误
你在for (const [x] of names)这一行犯了解构错误:names是字符串数组,并非键值对数组,[x]会取每个字符串的第一个字符,且后续代码里使用的name变量未在循环中定义,这会导致逻辑混乱,甚至无法正确调用异步API。
正确的遍历方式应为直接获取数组元素:
for (const name of names) {
错误2:未将Promise解析值替换回原对象
Promise.all仅会等待所有Promise完成并返回包含所有解析结果的数组,但不会自动把allNames对象中的Promise替换成解析后的值。因此即使await执行完毕,allNames里存储的依然是Promise对象,自然无法直接访问salary这类属性。
修正后的完整代码
let names = ["aaron", "bob", "john", "aaron"]; let allNames = {}; // 初始化对象并直接存储Promise,避免重复请求 names.forEach(name => { if (!allNames[name]) { allNames[name] = this.getNameData(name); } }); // 等待所有Promise完成,获取解析结果数组 const resolvedValues = await Promise.all(Object.values(allNames)); // 将解析结果对应回原对象的键 Object.keys(allNames).forEach((key, index) => { allNames[key] = resolvedValues[index]; }); // 现在可直接访问属性 console.log(allNames["john"].salary);
额外优化
可以合并初始化与存储Promise的步骤,无需先将值设为null再替换,第一次遇到名称时直接存储Promise即可,减少多余判断。
内容的提问来源于stack exchange,提问作者sal3jfc
相关产品推荐
相关产品推荐

