【问题标题】:AngularFire firestore get / snapshotchanges / valuechanges action on observable is not async?AngularFire firestore get / snapshotchanges / valuechanges 对 observable 的操作不是异步的吗?
【发布时间】:2021-01-23 07:27:18
【问题描述】:

您好,我的行为很奇怪。

我正在迭代一些文档并设置一些承诺,即当获取文档时,UI 会更新。

然而,虽然 promise 是原子的,但 firestore / AngularFire 会等待所有的 promise。

例子:

 for (const event of events) {
        this.eventService.getEventActivitiesAndSomeStreams(this.user,
          event.getID(),
          [DataLatitudeDegrees.type, DataLongitudeDegrees.type])
          .pipe(take(1)).toPromise().then((fullEvent) => {
            this.logger.info(`Promise completed`)
           
          })
      }

人们会期望随着数据的到来,对于每个承诺,它会慢慢打印完成的承诺。

但是它们都被打印一次。看起来这些承诺不是一个接一个,而是“一次完成”。在打印第一个控制台日志之前,等待时间很长,然后所有的 Promise 都会打印出来。

所以我希望如果我有一个进度条会增加一点点但很少但会立即增加

内部调用this.eventService.getEventActivitiesAndSomeStreams

return this.afs
        .collection('users')
        .doc(userID)
        .collection('events')
        .doc(eventID)
        .collection('activities')
        .doc(activityID)
        .collection('streams', ((ref) => {
          return ref.where('type', 'in', typesBatch);
        }))
        .get()
        .pipe(map((documentSnapshots) => {
          return documentSnapshots.docs.reduce((streamArray: StreamInterface[], documentSnapshot) => {
            streamArray.push(this.processStreamDocumentSnapshot(documentSnapshot)); // Does nothing rather to create an class of the JSON object passed back from the firestore
            return streamArray;
          }, []);
        }))

现在,如果我在 for 循环中放置一个 await,当然这可以正常工作并完成应有的承诺,但是这需要很多时间。

我也试过不使用AngularFire,使用原生的JS SDK效果一样。

我怀疑 IndexedDB 可能会导致这个或其他一些 Firebase 逻辑。

我在这里缺少什么,如果可能的话,我怎样才能获得所需的行为?

您可以通过 ["users" -> "events" -> "something"] firestore 集合复制此内容,如果每个“用户”有 500 个“事件”,并且每个事件还有 2 个文档。

因此,为用户获取所有事件并尝试为每个事件做出一个承诺,该承诺将在 for 数组中返回 2 个“某物”文档)

【问题讨论】:

  • 不确定提供的代码是否足够。你能分享完整的getEventActivitiesAndSomeStreamsprocessStreamDocumentSnapshot 方法吗?
  • @DipenShah processStreamDocumentSnapshot 只是一个 JSON 到类实例,只不过是从 JSON 返回中实例化一个对象。 getEventActivitiesAndSomeStreams 调用我上面写的“基本上”,它只有我在这里硬编码的 collection 名称等
  • 您可以通过“用户”->“事件”->“某事”重现此内容,其中每个“用户”可以说 500 个“事件”,每个事件还有 2 个文档。因此,为用户获取所有事件并尝试为每个事件做出承诺,该承诺将在 for 数组中返回 2 个“某物”文档
  • 为什么你会期望这里的东西一一迭代?您在一个 for 循环中激活所有流,这对于人类感知来说几乎是瞬时的,这意味着它们都基本上同时发出请求,因此它们应该基本上同时得到所有响应。您没有 async / await 语句或其他流控制工具告诉它一个一个地执行它们...如果您输入有关您想要发生的任何细节,那么我可以提供帮助,但就目前而言,一切都是行为完全符合预期。

标签: javascript firebase google-cloud-firestore angularfire2


【解决方案1】:

这种行为是意料之中的,与 firebase 毫无关系。您正在遍历数组并发送请求。项目之间没有等待或延迟,因此 for 循环(没有 await 语句)将在极短的时间内完成,这意味着所有请求都在几毫秒内发送出去,或者基本上同时发送.所以他们的回应也应该基本同时到达。

您已声明不想使用 await 语句并逐个迭代,因此很难确切知道您想要或期望发生什么。也许您希望它们相隔 0.5 秒?如果是这样,您需要编写该逻辑:

timer(0, 500).pipe( // put whatever ms time between requests you want here?
  take(events.length),
  switchMap(i => {
    return this.eventService.getEventActivitiesAndSomeStreams(this.user,
      events[i].getID(),
      [DataLatitudeDegrees.type, DataLongitudeDegrees.type]).pipe(take(1))
  })
).subscribe(fullEvent => {
  this.logger.info(`Promise completed`)
})

(删除的承诺会导致 idk 为什么首先使用它们,而使用 rxjs IMO 更容易进行这种控制)

【讨论】:

  • hmmm 但问题没有完成循环。是不是所有的“然后”的承诺都会在很长的等待时间内立即触发。
  • 这就是异步编程的工作原理。循环基本上同时发出所有请求,然后所有请求基本上同时返回,并且只要响应进入,then 处理程序就会运行。它不关心何时或如何发送。 “漫长的等待时间”就是处理请求所需的时间。如果发送一个或几个请求要快得多,那么您可能只是因为一次请求太多而对浏览器施加了压力。
  • 是的,我知道,但又一次。想象一个下载​​文件的进度条。这不是意味着其中一个 promises ,最小尺寸的那个,会首先进入“then”部分吗?这里几乎同时进入“then”部分。我们谈论的是一次完成的 500*1Mb 文件(API 读取)。这真的是设计的吗?我错过了什么?
  • 在响应时间有显着变化的文件下载的情况下,是的,您会看到这一点。但是在您的情况下,所有请求恰好花费了大致相同的时间。但是,如果您一次发出 500 个请求,那么您对浏览器的要求就太高了。
  • 一次 500 个请求也可能只是导致交通堵塞,因为您将开始遇到浏览器可以处理的阻塞点。您可能想探索批处理或最好设计为不一次发出那么多请求。想到的第一个解决方案是从 API 请求事件列表,而不是为每个单独的事件发出请求。
猜你喜欢
  • 1970-01-01
  • 2021-11-09
  • 2020-01-17
  • 1970-01-01
  • 2020-04-01
  • 1970-01-01
  • 1970-01-01
  • 2018-05-04
  • 2023-03-16
相关资源
最近更新 更多