我具有此功能,该功能遍历字符串数组,其中每个字符串代表用户的UID。该功能应该转到每个用户的个人资料,检查其最新信誉(类似于SO),然后将uid和信誉映射推送到新数组。
第二个数组总是空着,所以我放置了一些日志来检查发生了什么。这是我的功能:
candidates.forEach(async id => {
console.log('user log ' + id);
const snap2 = await db.doc('communities_data/' + community.id + '/profiles/' + id).get();
const user = snap2.data();
console.log('user ' + user);
if (user !== undefined) {
console.log(user + ' just user');
const reputation = (user.reputation as number);
candidatesWithReputation.push(new UserAndReputation(id, reputation));
} else {
console.log('user undefined ');
};
});
第一个显示'user log ' +id
的列始终会打印,并会按需打印用户ID,因此我知道第一个数组就可以了。
但是没有其他日志打印。曾经。我最初的想法是,也许我走错了路?但是我已经检查了一百万次,这是用户个人资料在我的数据库中的路径。
例如,这可以是配置文件的路径:
communities_data/hfd98HDKKhfEwe6W/profiles/bqSFS04LKJDbfhdwU
任何失败的主意
答案 0 :(得分:5)
我的猜测是您遇到时间问题。 .forEach()
在继续下一次迭代之前不会等待异步操作完成(它不会查看您的代码正在从异步回调返回的承诺),因此在.forEach()
之后在.forEach()
循环之后,数组将始终为空,因为它尚未被填充(循环中的异步调用尚未完成)。
因此,基本上,您很少想在async/await
回调中使用.forEach()
,因为循环不尊重它,并且在完成所有操作后您无法知道循环之外的情况。
虽然您没有为该代码显示更大的上下文,但是通常的解决方案是使用常规的for
lop或for/of
循环来等待await
语句这样您就可以更轻松地知道何时完成所有操作。
这是一种方法:
async function someFunction() {
// other code here
for (let id of candidates) {
try {
console.log('user log ' + id);
const snap2 = await db.doc('communities_data/' + community.id + '/profiles/' + id).get();
const user = snap2.data();
console.log('user ' + user);
if (user !== undefined) {
console.log(user + ' just user');
const reputation = (user.reputation as number);
candidatesWithReputation.push(new UserAndReputation(id, reputation));
} else {
console.log('user undefined ');
};
} catch(e) {
console.log(e);
// decide what to do upon error,
// skip it and proceed?
// stop further processing?
}
}
// candidatesWithReputation should now be valid here
console.log(candidatesWithReputation);
// other code here
}
请注意,必须声明包含函数async
,以使您可以在await
循环内使用for
。
为了获得更好的性能,您还可以并行执行所有这些查找,并使用Promise.all()
查看它们何时全部完成:
function someFunction() {
// other code here
Promise.all(candidates.map(id => {
return db.doc('communities_data/' + community.id + '/profiles/' + id).get().then(snap2 => {
return snap2.data();
}).catch(err => {
// decide what to do about an error here
// this implementation skips any queries with error and proceeds with the others
return undefined;
});
})).then(users => {
let candidatesWithReputation = [];
for (user of users) {
if (user !== undefined) {
// I've not seen this "user.reputation as number" syntax?? Typescript?
const reputation = (user.reputation as number);
candidatesWithReputation.push(new UserAndReputation(id, reputation));
}
}
return candidatesWithReputation;
}).then(users => {
// list of users with reputation here
console.log(users);
// further processing here
}).catch(err => {
console.log(err);
});
}