有没有一种有效的方法来跟踪rxjs中的订阅

时间:2019-12-08 16:58:56

标签: firebase google-cloud-firestore rxjs observable angularfire2

假设我有很多包含这样结构的组件

ngOnInit() {
    this.fb.user$.subscribe(data => {
        if (data != null) {
          //User is logged in
          this.fb.afs.collection('col').doc(data.info).valueChanges().subscribe(info => {
            this.info = info;
          })
          //Lots of other subscriptions following...
        } else {
          //User is logged out
        }
    })
}

用户注销后,会因为

而抛出Firebase权限异常
this.fb.afs.collection('col').doc(data.info).valueChanges().subscribe(info => {
  this.info = info;
})

不再允许订阅。

是否还有其他取消订阅所有Firebase订阅的方法,而无需将所有订阅手动推送到数组并在注销用户之前将其循环?

2 个答案:

答案 0 :(得分:2)

也许通过takeUntil运算符传递给每个运算符?

destroyed = new Subject();
destroyed$ = this.destroyed.asObservable();

constructor() {
  resource1$.pipe(takeUntil(this.destroyed$)).subscribe(...);
  resource2$.pipe(takeUntil(this.destroyed$)).subscribe(...);
  resource3$.pipe(takeUntil(this.destroyed$)).subscribe(...);
}


ngOnDestroy() {
  this.destroyed.next();
  this.destroyed.complete();
}
  

takeUntil:发射值,直到提供可观察到的发射为止。

答案 1 :(得分:1)

首先,不建议在rxjs中使用嵌套订阅,对于这种逻辑,请使用switchMap运算符。

要管理组件中的订阅,可以创建一个Subscription()并在其上使用add函数。请参见下面的示例:

import { Subscription } from 'rxjs';

@Component({...})
export class TestComponent implements OnInit, OnDestroy {

private readonly subscriptions = new Subscription()

ngOnInit() {
    const firstSubscription = stream1$.subscribe(...);
    const secondSubscription = stream2$.subscribe(...);
    this.subscriptions.add(firstSubscription);
    this.subscriptions.add(secondSubscription);
}

ngOnDestroy() {
    this.subscriptions.unsubscribe();
}

这里还有一个更复杂的流管理示例:

import { Subscription, of } from 'rxjs';
import { switchMap, tap } from 'rxjs/operators';

@Component({...})
export class TestComponent implements OnInit, OnDestroy {

ngOnInit() {
    const userSubscription = this.fb.user$.pipe(
        switchMap(data => {
            if (data) {
                return this.fb.afs.collection('col').doc(data.info).valueChanges();
            } else if (1 !== 2) { // for example
                return this.anotherService.getDataById(data.id).pipe(
                    tap((cat) => {
                        // here you can also do some intermediate logic
                        this.cats = [cat];
                    })
                )
            }
            // other things to be returned

            // don't forget to olways pass something. 
            // if nothing matched, return default value
            return of(null);
        })
    ).subscribe(info => {
        this.info = info;
    });
    this.subscriptions.add(userSubscription);
    const anotherSubscription = this.anotherService.mockMethod.subscribe(() => /** 
    something */);
    this.subscriptions.add(anotherSubscription);
}

ngOnDestroy() {
    this.subscriptions.unsubscribe();
}

}


所以在这里您应该注意两件事:

  1. 与您的问题有关的内容:获取对订阅userSubscription的引用(由.subscribe()方法返回,并将其添加到组件subscriptions中。然后在{{1 }}取消订阅该组件中的所有订阅。您可以根据需要添加任意数量。

  2. 不使用嵌套订阅。使用管道可以让您控制流并制作rxjs提供的许多很棒的功能。这是延迟,过滤,映射等等。我建议您学习更多有关扁平化策略(flatMap,switchMap,concatMap和haustMap)的信息。查看本文https://medium.com/@shairez/a-super-ninja-trick-to-learn-rxjss-switchmap-mergemap-concatmap-and-exhaustmap-forever-88e178a75f1b,并在那里观看视频。我认为这是对此主题的最佳解释。