Firebase 如何防止我的可观察订阅针对每个发出的值再次运行?
我有一段很长的代码,其中包含一些嵌套的订阅和事务等Firebase 如何防止我的可观察订阅针对每个发出的值再次运行?,firebase,google-cloud-firestore,rxjs,observable,Firebase,Google Cloud Firestore,Rxjs,Observable,我有一段很长的代码,其中包含一些嵌套的订阅和事务等 updateActivity(value, index) { return this.currentDay.subscribe(docRef => { let dayRef = this.db.collection('days').doc(docRef[0].payload.doc.id); let innerRef = dayRef.collection('session').doc(index.to
updateActivity(value, index) {
return this.currentDay.subscribe(docRef => {
let dayRef = this.db.collection('days').doc(docRef[0].payload.doc.id);
let innerRef = dayRef.collection('session').doc(index.toString())
return this.db.firestore.runTransaction(function(transaction) {
return transaction.get(innerRef.ref).then(function() {
console.log("outermost")
innerRef.valueChanges().subscribe(toRollback => {
console.log("toRollback: " + toRollback)
dayRef.valueChanges().subscribe(toUpdate => {
console.log("toUpdate: " + toUpdate)
dayRef.update({
caloriesBurned: toUpdate["caloriesBurned"] - toRollback["caloriesBurned"],
sessionTime: toUpdate["sessionTime"] - toRollback["duration"] })
})
})
transaction.set(innerRef.ref, value);
})
})
})
}
要点是这个dayRef.update()
调用更新Firebase中的一个集合。集合更新后,dayRef.valueChanges()
订阅将意识到有一个新值要发出并再次运行,它将不断重复更新dayRef
。这将导致一个无限循环
理想的行为是,我订阅这个可观察对象,然后,使用从可观察对象发出的值,更新可观察对象从中导出其旧值的Firebase集合。由于订阅仍处于活动状态,因此每次更新时,dayRef.update()
调用将继续执行
我理解这可能是对可观测事物的根本误解。从逻辑上讲,这里发生的事情对我来说是有意义的,但我不确定在不订阅的情况下如何使用这些值,也不确定如何正确地取消订阅。我已经尝试在每个可观察的块的末尾运行.unsubscribe()
,但这只是在值发出之前同步取消订阅
编辑:使用switchMap
dayRef.valueChanges().pipe(switchMap(toUpdate =>
innerRef.valueChanges().pipe(switchMap(toRollback =>
dayRef.update({
caloriesBurned: toUpdate["caloriesBurned"] - toRollback["caloriesBurned"],
sessionTime: toUpdate["sessionTime"] - toRollback["duration"] })
))
))
编写嵌套订阅确实是一种非常糟糕的做法。而是链接rxjs操作符。 在您的示例中,我认为switchMap非常适合。取决于你想要完成什么 见文件: 编辑: 此外,尝试在事务之前定义大部分可观察的逻辑。如果可以,请在
updateActivity()
函数之外定义它
例如:
let dayRef$ = this.currentDay.pipe(
switchMap(docRef => this.db.collection('days').doc(docRef[0].payload.doc.id))
);
let innerRef$ = dayRef$.pipe(
map(dayRef => dayRef.collection('session').doc(index.toString()))
);
表示您的观察值。在事务中使用
valueChanges
听起来不是个好主意。如果您需要在事务中处理文档,您应该只使用传递给事务处理程序的事务
对象。嘿,我已经尝试过了,但我看不出switchMap有什么真正的区别。当我订阅内部使用switchMap的管道时,同样的无限循环效果也会出现。我已经在我的答案中添加了代码,但我仍然不确定我是否正确使用了switchMap。我想你还不明白它是如何工作的。当您从一个可观察对象订阅时,您将切换到一个同步上下文。因此,在subscribe中执行的代码在发出的每个新值处执行。您的第一段代码在innerRef.valueChanges()
的每个新值处为您的dayRef.valueChanges()
创建一个新订阅。你能看到问题所在吗?我已经将这里的一些处理带到了一个运行得更好的云函数。该函数几乎按预期工作,但它仍然卡在与第一次订阅相关的更新循环中。如您所示,我尝试使用switchMap获取dayRef,但是.doc
没有返回可观察值,因此操作员抱怨。我尝试改用map
,但这仍然会产生相同的效果。之后我仍然必须订阅dayRef$
,因此每次我更新day
集合时,它仍然会发出一个新值。请尝试在整个过程中只使用一个子项。如果您有这样的能力,不仅可以轻松跟踪您的流程,还可以解决许多错误。适应这种看待事物的方式需要一些时间,但一旦你做到了,这是值得的。