Angular 如何控制rxjs中的间隔在角模式下禁用计时器

Angular 如何控制rxjs中的间隔在角模式下禁用计时器,angular,rxjs,Angular,Rxjs,我尝试在angular应用程序中实现一种“会话计时器”。当用户在指定时间段内未单击任何键时,它将注销用户。一切正常,直到第一次注销。第二次登录后,计时器的重置方法不起作用。无论执行何种操作,用户都会在指定时间后注销 我在上做了一个演示 以下是服务代码: @Injectable({ providedIn: "root" }) export class SessionTimerService { private readonly sessionTimer: Observable<num

我尝试在angular应用程序中实现一种“会话计时器”。当用户在指定时间段内未单击任何键时,它将注销用户。一切正常,直到第一次注销。第二次登录后,计时器的重置方法不起作用。无论执行何种操作,用户都会在指定时间后注销

我在上做了一个演示

以下是服务代码:

@Injectable({
  providedIn: "root"
})
export class SessionTimerService {
  private readonly sessionTimer: Observable<number> = interval(10000); // 10 sec
  private sessionTimerController: Subject<void>;

  public constructor(private readonly router: Router) {}

  public initTimer(): void {
    this.sessionTimerController = new Subject<void>();
    this.sessionTimer
      .pipe(
        take(1),
        takeUntil(this.sessionTimerController)
      )
      .subscribe(() => {
        console.log("logout");
        this.sessionTimerController.next();
        this.sessionTimerController.complete();
        this.router.navigate(["/login"]);
      });
  }

  public resetTimer(): void {
    if (this.sessionTimerController && !this.sessionTimerController.closed) {
      console.log("reset");
      this.sessionTimerController.next();
      this.sessionTimerController.complete();

      this.initTimer();
    }
  }

  public stopTimer(): void {
    if (this.sessionTimerController && !this.sessionTimerController.closed) {
      console.log("stop");
      this.sessionTimerController.next();
      this.sessionTimerController.complete();
    }
  }
}
@可注入({
提供于:“根”
})
导出类SessionTimerService{
私有只读会话计时器:可观察=间隔(10000);//10秒
私有sessiontimecontroller:主题;
公共构造函数(专用只读路由器:路由器){}
public initTimer():void{
this.sessionTimerController=新主题();
这是sessionTimer
.烟斗(
以(1)为例,
takeUntil(此.sessionTimerController)
)
.订阅(()=>{
控制台日志(“注销”);
this.sessiontimecontroller.next();
this.sessiontimecontroller.complete();
this.router.navigate([“/login”]);
});
}
公共重置计时器():void{
if(this.sessiontimecontroller&!this.sessiontimecontroller.closed){
控制台日志(“重置”);
this.sessiontimecontroller.next();
this.sessiontimecontroller.complete();
this.initTimer();
}
}
公共停止计时器():void{
if(this.sessiontimecontroller&!this.sessiontimecontroller.closed){
控制台日志(“停止”);
this.sessiontimecontroller.next();
this.sessiontimecontroller.complete();
}
}
}

window.relad()
不是这个问题的好答案。

问题是,在第二次登录时,您正在创建两个独立的计时器,因为第一次登录时是
this.sessionTimerController===null
,并且您检查了以下条件:

  • 内部
    onMouseMove
  • main组件的构造函数中
  • 第二个问题是方法
    initTimer()
    没有检查是否已经有计时器运行:

    因此,在创建新计时器之前,您可以完成上一个计时器,以便知道始终只有一个:

    private sessionTimerController: Subject<void> = new Subject<void>();
    
    ...
    
    public initTimer(): void {
      console.log('initTimer');
    
      this.sessionTimerController.next();
      this.sessionTimerController.complete();
      this.sessionTimerController = new Subject<void>();
      ...
    
    private sessionTimerController:Subject=newsubject();
    ...
    public initTimer():void{
    log('initTimer');
    this.sessiontimecontroller.next();
    this.sessiontimecontroller.complete();
    this.sessionTimerController=新主题();
    ...
    
    现场演示:


    在我看来,在您的用例中,完全摆脱
    主题将更容易,因为这只会使事情变得复杂,并使用单个
    订阅
    对象来取消任何以前的计时器。

    问题是,您在第二次登录时创建了两个独立的计时器,因为在第一次登录时是
    this.sessionTimerController===null
    ,您可以检查以下条件:

  • 内部
    onMouseMove
  • main组件的构造函数中
  • 第二个问题是方法
    initTimer()
    没有检查是否已经有计时器运行:

    因此,在创建新计时器之前,您可以完成上一个计时器,以便知道始终只有一个:

    private sessionTimerController: Subject<void> = new Subject<void>();
    
    ...
    
    public initTimer(): void {
      console.log('initTimer');
    
      this.sessionTimerController.next();
      this.sessionTimerController.complete();
      this.sessionTimerController = new Subject<void>();
      ...
    
    private sessionTimerController:Subject=newsubject();
    ...
    public initTimer():void{
    log('initTimer');
    this.sessiontimecontroller.next();
    this.sessiontimecontroller.complete();
    this.sessionTimerController=新主题();
    ...
    
    现场演示:


    在我看来,在您的用例中,完全摆脱
    主题将更容易,因为这只会使事情变得复杂,并使用单个
    订阅
    对象来取消任何以前的计时器。

    RXJS功能强大,您可以
    取消订阅正在进行的事件,因此我在这个解决方案中设法做到这一点n

    这是服务代码

    
    @注射的({
    提供于:“根”
    })
    导出类SessionTimerService{
    savedSub:订阅;
    公共构造函数(专用只读路由器:路由器){
    }
    public initTimer():void{
    this.savedSub=of(true).pipe(延迟(5000))
    .订阅(()=>{
    this.router.navigate(['login']);
    this.savedSub.unsubscribe();
    })
    }
    公共重置计时器():void{
    if(this.savedSub){
    this.savedSub.unsubscribe();
    this.savedSub=null;
    this.initTimer();
    }
    }
    onDestroy(){
    if(this.savedSub){
    this.savedSub.unsubscribe();
    this.savedSub=null;
    }
    }
    }
    
    initTimer将等待5秒。当没有任何东西可以阻止它时,它将注销 当您拥有的订阅引用
    取消订阅时
    将消失,并且不会触发。。 单击鼠标,我们将
    取消订阅
    并从开始重新运行计时器

    但是如果无人停止计时器,您需要取消订阅或
    null
    订阅的值..这就是为什么我们在
    ngondestory
    工作时从主组件调用
    onDestroy

    ngondestory(){
    this.sessionTimer.onDestroy();
    }
    

    希望这能解决您的问题。

    RXJS功能强大,您可以
    取消订阅正在进行的活动,所以我在这个解决方案中做到了这一点

    这是服务代码

    
    @注射的({
    提供于:“根”
    })
    导出类SessionTimerService{
    savedSub:订阅;
    公共构造函数(专用只读路由器:路由器){
    }
    public initTimer():void{
    this.savedSub=of(true).pipe(延迟(5000))
    .订阅(()=>{
    this.router.navigate(['login']);
    this.savedSub.unsubscribe();
    })
    }
    公共重置计时器():void{
    if(this.savedSub){
    this.savedSub.unsubscribe();
    this.savedSub=null;
    this.initTimer();
    }
    }
    onDestroy(){
    if(this.savedSub){
    this.savedSub.unsubscribe();
    this.savedSub=null;
    }
    }
    }
    
    initTimer将等待5秒。当没有任何东西可以阻止它时,它将注销 当订阅