我有一个函数,它迭代一个字符串数组,其中每个字符串代表一个用户的 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
知道哪里失败了
最佳答案
我的猜测是您遇到了时间问题。 .forEach()
在继续下一次迭代之前不会等待异步操作完成(它不会查看代码从异步回调返回的 promise ),因此在 .forEach()
之后,您的第二个数组在 .forEach()
循环之后将始终为空,因为它尚未填充(循环中的异步调用尚未完成)。
所以基本上,您很少想在 .forEach()
回调中使用 async/await
,因为循环不尊重它,并且您无法知道循环外的一切何时完成。
虽然您没有显示此代码的更大上下文,但这里通常的解决方案是使用常规的 for
循环或 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
才能允许您在 for
循环内使用 await
。
为了获得更好的性能,您还可以并行执行所有这些查找,并使用 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);
});
}
关于node.js - 等待函数永远不会执行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57403552/