I'm trying to manage a timer in an Angular 2 environment, and clearTimeout seems to only work correctly about half the time. I am writing in TypeScript.
I keep the timer in its own service:
export class TimeoutService {
constructor(
private router: Router,
private httpService: HttpService
) {}
//Properties
private timer;
//Methods
public clearTimer() {
clearTimeout(this.timer);
}
private logOut() {
return this.httpService.Post('api/session/logout', '');
}
private redirectToTimeoutPage() {
this.router.navigate(['/timeout']);
}
public refreshTimer() {
console.log('refreshing timer');
if (this.timer) {
this.clearTimer();
this.setTimer();
}
}
public startTimer() {
this.setTimer();
}
private setTimer() {
this.timer = setTimeout(() => {
this.logOut()
.then(() => {
this.clearTimer();
this.redirectToTimeoutPage();
});
}, 30000);
}
}
I know from the console.log in the refreshTimer method that it is being called when I expect it to be, and not otherwise. However, most of the time, earlier timers will not be canceled by the clearTimeout call, and will fire once their thirty seconds is up even though they should have been replaced by a new timer.
I've been through the other SO questions about this and none applies to my situation as far as I can see.
The one clue I've got, which I can't decipher, is that if I remove the call to this.setTimer()
within refreshTimer, then the clearTimeout call seems to work fine. In other words, creating a new timer is somehow causing the old one to survive. What am I missing here?
Thank you!
In refreshTimer
you take care of calling this.clearTimer()
before calling this.setTimer()
.
However, in startTimer
, you do not call this.clearTimer()
. So if the calling code calls startTimer
more than once without doing anything that calls this.clearTimer
in between, you're going to start multiple timeouts, but only the last one will be remembered by your class and cancelled when this.clearTimer
is called again.
In your clearTimeout
function, you not only want to clear the timer, but you also want to reset your timer
variable:
public clearTimer() {
clearTimeout(this.timer);
this.timer = null; // <-- You also want your variable to become null here.
}
Then, any code that runs after a call to clearTimer()
will correctly evaluate the timer
variable as null
which correctly indicates that no timer exists. Simply stopping the running timer isn't enough for your wrapper.
Also (FYI), as I said in the comments, it's a very good best-practice to initialize all your variables so no "surprise" values appear out of no where.
private timer;
Should be:
private timer = null;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With