Angular 如何防止从这个角度泄漏6 rxjs 6

Angular 如何防止从这个角度泄漏6 rxjs 6,angular,Angular,我在authService.ts中有以下函数 它可以工作,但是订阅泄露了。它存在于一项服务中,几乎每个组件都在整个应用程序中使用 mouseEvents: Subscription; timer: Subscription; constructor() { if(user){ this.updateOnIdle(user.uid); } } private updateOnIdle(userId) { this.mo

我在authService.ts中有以下函数

它可以工作,但是订阅泄露了。它存在于一项服务中,几乎每个组件都在整个应用程序中使用

   mouseEvents:  Subscription;
    timer: Subscription;

    constructor() {
      if(user){
        this.updateOnIdle(user.uid);
      }
    }

private updateOnIdle(userId) {
  this.mouseEvents =  fromEvent(document, 'mousemove')
                       .pipe(
                        throttleTime(2000)
                      )
                      .subscribe(() => {
                        firebase.database().ref('/status/' + userId).set({
                          status: 'online',
                          last_changed: firebase.database.ServerValue.TIMESTAMP
                      });
                        this.resetTimer(userId)
                     });
}

/// Reset the timer
private resetTimer(userId) {
  if (this.timer) {this.timer.unsubscribe()}

  this.timer = timer(5000)
                  .map(() => {
                    firebase.database().ref('/status/' + userId).set({
                      status: 'away',
                      last_changed: firebase.database.ServerValue.TIMESTAMP
                  });
                  }).subscribe();
}

我如何解决这个问题?编写函数的更好方法是什么?

解决泄漏问题的一个方法是不要在
ts
中使用订阅,而是返回可观察值,让angular的
async
管道为您管理订阅

mouseEvents$:  Observable<any>;
timer$: Observable<any>;

constructor() {
  if(user){
    this.updateOnIdle(user.uid);
  }
}

private updateOnIdle(userId) {
  this.timer$ =  fromEvent(document, 'mousemove')
                       .pipe(
                        throttleTime(2000),
                        switchMap(() => firebase.database().ref(`/status/${userId}`).set({status: 'online', last_changes: firebase.database.ServerValue.TIMESTAMP}),
                        map(your reset timer logic here)
                      );
                        this.resetTimer(userId);
                     });
}
mouseEvents$:可观察;
计时器$:可观察;
构造函数(){
如果(用户){
this.updateOnIdle(user.uid);
}
}
私有updateOnIdle(用户ID){
this.timer$=fromEvent(文档“mousemove”)
.烟斗(
节流时间(2000年),
switchMap(()=>firebase.database().ref(`/status/${userId}').set({status:'online',last_changes:firebase.database.ServerValue.TIMESTAMP}),
映射(此处为重置计时器逻辑)
);
这个.resetTimer(userId);
});
}
然后在html中使用它

<div class="myTimer" [time]="timer$ | async"></div>

从可观察对象取消订阅有不同的方式,您可以调用取消订阅方法,也可以使用自动取消订阅的运算符之一:

  • 第一:将在第一次火灾后完成并取消订阅
  • take:将在n次激发后完成并取消订阅
  • takeUntil:当通过的可观察到的事件发生时,将完成并取消订阅
  • takeWhile:将在条件不再为真时完成并取消订阅

您可以为您的案例选择合适的操作员。

在回答您后面的问题后,我刚刚看到了这个问题。我现在可以看到更大的图景,以及为什么在另一个问题中没有
subscribe()
调用

本质上,我认为“泄漏”是指在使用该服务的组件被销毁后,鼠标事件继续触发

如果是这样,那么处理它的方法可能是统计服务内部的引用,并在最后一个停止时取消订阅()。大概

@Injectable()
导出类MyService{
mouseEvents:订阅;
定时器:订阅;
参考值=0;
构造函数(){
}
公共启动(){
如果(!参考){
this.updateOnIdle(user.uid);
}
参考文献+=1;
}
公众站{
参考文献-=1;
如果(!参考){
mouseEvents.unsubscribe();
timer.unsubscribe();
}
}
私有updateOnIdle(用户ID){
...
}
在组件中

@Component()
导出类MyComponent实现OnInit、OnDestroy{
建造师(
私有myService:myService
) {}
恩戈尼尼特(){
myService.start();
}
恩贡德斯特罗(){
myService.stop();
}

事实上,我在html中不需要它。只是为了更新数据库。如果你需要更新数据库,你可以在数据库更新后取消订阅。谢谢。但是在你的答案中我将把上面的unsubscribe()方法放在哪里呢?我正在与RXJS作斗争。你只需在
管道()之后加上
。unsubscribe()