如何防止 ng2-idle 在每次成功登录时多次实例化

how to pevent ng2-idle instantiating multiple times with each successful login

我在将空闲时间设置为在会话到期前一分钟显示弹出窗口时遇到问题。然后会话超时或用户注销。下次用户登录时,他们现在在超时时有 2 个弹出窗口。用户注销并再次登录,现在有 3 个弹出窗口,依此类推。如何在用户注销时销毁当前的 Idle 实例?

我的设置如下:

constructor(private idle: Idle, ...) {}

ngOnInit() {
    this.setIdle();
}

private setIdle() {
    // Client activity timeout. 29 minutes to 'idle', 1 minute beyond that to timeout
    this.ngZone.runOutsideAngular(() => {
        // this.idle.setIdle(29 * 60);
        // this.idle.setTimeout(1 * 60);
        this.idle.setIdle(10);
        this.idle.setTimeout(10);
        this.idle.setInterrupts(DEFAULT_INTERRUPTSOURCES);
    });


    this.idle.onTimeout.subscribe(() => {
        this.ngZone.run(() => {
            this.errorDialogRef.close();
            sessionStorage.setItem('sessionExpired', 'true');
            this.displayErrorModal(true);
        });

    });

    this.idle.onIdleStart.subscribe(() => {
        this.ngZone.run(() => {
            this.displayIdleWarning();
        });
    });

    this.ngZone.runOutsideAngular(() => {
        this.idle.watch();
    });
}

在注销过程中,我尝试了 this.idle.stop()delete this.idle。但都没有用。

仅供参考:它必须 运行 在 angular 区域之外,否则我们的量角器测试会中断。

更新: 在找到将数组归零的解决方案之前,我确实尝试过:

this.idle.onTimeout.unsubscribe();
this.idle.onIdleStart.unsubscribe();
this.idle.onIdleEnd.unsubscribe();

但这只会导致在随后的登录过程中出现以下错误:

core.es5.js?0445:1084 ERROR Error: Uncaught (in promise): ObjectUnsubscribedError: object unsubscribed 

在我看来,我的组件保留了它的引用,或者在注销期间没有被销毁。

我能够检查 this.idle 对象并发现 "do stuff" 对象(onTimeoutonIdleStartonIdleEndonInterrupt,和 onTimeoutWarning) 是 EventEmitter。每个都有一个名为 observers 的对象。 observers 是一个观察者数组。每次创建新的弹出窗口时,我都会注意到数组增加了。所以,在注销过程中,我只是清除了观察者:

this.idle.stop();
this.idle.onTimeout.observers.length = 0;
this.idle.onIdleStart.observers.length = 0;
this.idle.onIdleEnd.observers.length = 0;

这可能不是最好的方法。我确信有更好的方法可以从 EventEmitter 中删除观察者。但是我找不到它,这是一种快速而肮脏的方法。

我认为能够取消订阅观察者的正确方法是使用订阅变量进行订阅,而不是将观察者数组长度设置为 0。您问题中的代码几乎是正确的。您尝试的是:

this.idle.onTimeout.unsubscribe();

这将结束 this.idle.onTimeout 对 this.idle.onTimeout 订阅的可观察对象的订阅(这就是您收到 ObjectUnsubscribedError 错误的原因)。

本来可行的是这样的:

private idleOnTimeout$: Subscription;

// Subscribe in for example ngOnInit()
this.idleOnTimeout$ = this.idle.onTimeout.subscribe();

// Unsubscribe on ngOnDestroy()
this.idleOnTimeout$.unsubscribe();

ng-idle 的示例代码没有涵盖这一点,因为在他们的示例中,ng-idle 存在于应用程序的主要组件中,除非您完全重新加载页面(这也会重置 ng-idle),否则该组件永远不会被破坏。