我正在编写一个Firebase函数(Gist(,
-
以以下方式查询实时数据库ref(事件(:
await admin.database().ref('/events_geo').once('value').then(snapshots => {
-
遍历所有事件
snapshots.forEach(snapshot => {
-
事件通过标准进行过滤,以进一步处理
-
向实时数据库发出多个查询,以获取与事件相关的详细信息
await database().ref("/ratings").orderByChild('fk_event').equalTo(snapshot.key).once('value').then(snapshots => {
-
为SendGrid准备数据,并完成处理
所有的数据处理都很好,但我无法让外部等待(列表中的第1点(等待内部等待(向实时数据库查询(,因此当应该调用SendGrid时,数据是空的。数据稍后到达。Firebase功能日志的输出示例如下:
10:54:12.642 AM Function execution started
10:54:13.945 AM There are no emails to be sent in afterEventHostMailGoodRating
10:54:14.048 AM There are no emails to be sent in afterEventHostMailBadRating
10:54:14.052 AM Function execution took 1412 ms, finished with status: 'ok'
10:54:14.148 AM <p style="margin: 1em 0px;">Super hyggelig aften :)</p><p style="margin: 1em 0px;">super oplevelse, ... long string generated
Gist显示有问题的功能
我可能混淆了我的异步/等待,因为等待中有等待。但我不知道如何在不将代码拆分为多个原子块的情况下编写代码,但这仍然需要将一堆等待拼接在一起,使其更难阅读。
所以,总共两个问题。这段代码能工作吗?处理这种模式的理想方法是什么?在从RealtimeDB获取的数据之上进行进一步处理?
致以最良好的问候,Simon
您的问题是在foreEach
循环中使用async
:
Object.keys(event.participants).forEach(async (value: any) => {
forEach
循环不支持异步调用。您需要将数据映射到一个普通数组,并使用for
循环。在那里你可以正常使用await
。
我最终重构了这个函数,因为我意识到由于Tarik Huber的回答,它可以变得更简单。
关键点是:
- 不使用
forEach
,而是使用for(const event of events)
进行迭代,因为这与异步调用兼容 - 将功能拆分为更多的模块化部分。一个部分现在获取、过滤并存储数组中的数据。第二部分遍历数组并进行更多异步调用
这导致代码可读性更强,也更容易调试。旧函数一次性完成了上面提到的两个部分,并错误地使用了forEach
,这导致了异步调用无法正确解决的问题。
下面可以看到新功能的概要。只突出显示了重要部分。
async function afterEventHostMail() {
// Initialize variables
events = [];
await admin.database().ref('/events_geo').once('value').then(snapshots => {
snapshots.forEach(snapshot => {
var event = snapshot.val();
var eventKey = snapshot.key;
// Do some filtering
const mergedObj = { ...event, ...{ key: eventKey } };
events.push(mergedObj)
});
});
for (const event of events) {
// Do a ton of await calls here
}
// The rest of the function
}