run idle timer outside of angular zone

This commit is contained in:
Art Lowel
2021-06-15 15:48:10 +02:00
committed by Marie Verdonck
parent e88baa1995
commit 91b4c81986
3 changed files with 60 additions and 12 deletions

View File

@@ -1,7 +1,13 @@
import { Injectable } from '@angular/core'; import { Injectable, NgZone } from '@angular/core';
import { combineLatest as observableCombineLatest, Observable, of as observableOf, timer } from 'rxjs'; import {
import { catchError, filter, map, switchMap, take, tap } from 'rxjs/operators'; combineLatest as observableCombineLatest,
Observable,
of as observableOf,
timer,
asyncScheduler, queueScheduler
} from 'rxjs';
import { catchError, filter, map, switchMap, take, tap, observeOn } from 'rxjs/operators';
// import @ngrx // import @ngrx
import { Actions, Effect, ofType } from '@ngrx/effects'; import { Actions, Effect, ofType } from '@ngrx/effects';
import { Action, select, Store } from '@ngrx/store'; import { Action, select, Store } from '@ngrx/store';
@@ -43,8 +49,8 @@ import { hasValue } from '../../shared/empty.util';
import { environment } from '../../../environments/environment'; import { environment } from '../../../environments/environment';
import { RequestActionTypes } from '../data/request.actions'; import { RequestActionTypes } from '../data/request.actions';
import { NotificationsActionTypes } from '../../shared/notifications/notifications.actions'; import { NotificationsActionTypes } from '../../shared/notifications/notifications.actions';
import { ObjectCacheActionTypes } from '../cache/object-cache.actions'; import { LeaveZoneScheduler } from '../utilities/leave-zone.scheduler';
import { NO_OP_ACTION_TYPE } from '../../shared/ngrx/no-op.action'; import { EnterZoneScheduler } from '../utilities/enter-zone.scheduler';
// Action Types that do not break/prevent the user from an idle state // Action Types that do not break/prevent the user from an idle state
const IDLE_TIMER_IGNORE_TYPES: string[] const IDLE_TIMER_IGNORE_TYPES: string[]
@@ -261,22 +267,26 @@ export class AuthEffects {
@Effect() @Effect()
public trackIdleness$: Observable<Action> = this.actions$.pipe( public trackIdleness$: Observable<Action> = this.actions$.pipe(
filter((action: Action) => !IDLE_TIMER_IGNORE_TYPES.includes(action.type)), filter((action: Action) => !IDLE_TIMER_IGNORE_TYPES.includes(action.type)),
// Using switchMap the timer will be interrupted and restarted if a new action comes in, so idleness timer restarts // Using switchMap the effect will stop subscribing to the previous timer if a new action comes
switchMap(() => { // in, and start a new timer
return timer(environment.auth.ui.timeUntilIdle); switchMap(() =>
}), // Start a timer outside of Angular's zone
map(() => { timer(environment.auth.ui.timeUntilIdle, new LeaveZoneScheduler(this.zone, asyncScheduler))
return new SetUserAsIdleAction(); ),
}) // Re-enter the zone to dispatch the action
observeOn(new EnterZoneScheduler(this.zone, queueScheduler)),
map(() => new SetUserAsIdleAction()),
); );
/** /**
* @constructor * @constructor
* @param {Actions} actions$ * @param {Actions} actions$
* @param {NgZone} zone
* @param {AuthService} authService * @param {AuthService} authService
* @param {Store} store * @param {Store} store
*/ */
constructor(private actions$: Actions, constructor(private actions$: Actions,
private zone: NgZone,
private authService: AuthService, private authService: AuthService,
private store: Store<AppState>) { private store: Store<AppState>) {
} }

View File

@@ -0,0 +1,19 @@
import { SchedulerLike, Subscription } from 'rxjs';
import { NgZone } from '@angular/core';
/**
* An RXJS scheduler that will re-enter the Angular zone to run what's scheduled
*/
export class EnterZoneScheduler implements SchedulerLike {
constructor(private zone: NgZone, private scheduler: SchedulerLike) { }
schedule(...args: any[]): Subscription {
return this.zone.run(() =>
this.scheduler.schedule.apply(this.scheduler, args)
);
}
now (): number {
return this.scheduler.now();
}
}

View File

@@ -0,0 +1,19 @@
import { SchedulerLike, Subscription } from 'rxjs';
import { NgZone } from '@angular/core';
/**
* An RXJS scheduler that will run what's scheduled outside of the Angular zone
*/
export class LeaveZoneScheduler implements SchedulerLike {
constructor(private zone: NgZone, private scheduler: SchedulerLike) { }
schedule(...args: any[]): Subscription {
return this.zone.runOutsideAngular(() =>
this.scheduler.schedule.apply(this.scheduler, args)
);
}
now (): number {
return this.scheduler.now();
}
}