使用wait/async管理嵌套的Firebase实时数据库查询



我正在编写一个Firebase函数(Gist(,

  1. 以以下方式查询实时数据库ref(事件(:

    await admin.database().ref('/events_geo').once('value').then(snapshots => {

  2. 遍历所有事件

    snapshots.forEach(snapshot => {

  3. 事件通过标准进行过滤,以进一步处理

  4. 向实时数据库发出多个查询,以获取与事件相关的详细信息

    await database().ref("/ratings").orderByChild('fk_event').equalTo(snapshot.key).once('value').then(snapshots => {

  5. 为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的回答,它可以变得更简单。

关键点是:

  1. 不使用forEach,而是使用for(const event of events)进行迭代,因为这与异步调用兼容
  2. 将功能拆分为更多的模块化部分。一个部分现在获取、过滤并存储数组中的数据。第二部分遍历数组并进行更多异步调用

这导致代码可读性更强,也更容易调试。旧函数一次性完成了上面提到的两个部分,并错误地使用了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
}

最新更新