Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

clearTimeout fails sporadically

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!

like image 853
Nat Webb Avatar asked Jan 04 '23 20:01

Nat Webb


2 Answers

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.

like image 120
Louis Avatar answered Jan 13 '23 10:01

Louis


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;
like image 34
Scott Marcus Avatar answered Jan 13 '23 09:01

Scott Marcus