I was using setTimeouts for a project where a callback will be called after a duration, but the user has the options of extending, pausing or stopping the timeout. I felt using the default setTimeout was a bit clunky, especially since I needed to remember the timeout ids, and I decided to create a timeout utility object. I was wondering if I'm doing this properly, and whether you could give me some tips on how to refactor my code?
Object definition
//Utility object that makes it easier to control timeouts
function Timer(duration, callback) {
this._duration = duration;
this._callback = callback;
this._id = -1;
this._paused = true;
this._lastRunTime = -1;
this._remainingTime = this._duration;
}
//calls the current timeout; if a function is passed, run that function
//instead of default callback (but do not change the default callback)
Timer.prototype.callTimer = function(aCallback, aDuration) {
var that = this,
//sets callback and duration to default values if not passed in
callback = aCallback || this._callback,
duration = aDuration || this._duration;
//if a previous timeout has been set, clear it
if (this._id > -1 ) {
clearTimeout(this._id);
}
//executes the callback and resets the timer
this._id = setTimeout(function() {
callback();
that.resetTimer();
}, duration);
this._paused = false;
//rememebers the time when the timer was run (for pauseTimer)
this._lastRunTime = new Date();
}
Timer.prototype.resetTimer = function() {
this._remainingTime = this._duration;
this._paused = true;
this._lastRunTime = -1;
clearTimeout(this._id);
}
//changes the default callback
//if second argument is true, execute callTimer
Timer.prototype.changeCallback = function(callback, callTimer) {
this._callback = callback;
if (callTimer) this.callTimer();
}
Timer.prototype.pauseTimer = function() {
if (this._lastRunTime === -1) {
throw new Error('Timer has not been run yet');
}
//if currently paused, call timer with remaining time left
if (this._paused) {
this._lastRunTime = new Date();
this.callTimer(this._callback, this._remainingTime);
}
//else pause
else {
clearTimeout(this._id);
//subtract the amount of time that has elapsed
this._remainingTime -= (new Date() - this._lastRunTime);
}
//toggles the _paused variable
this._paused = !this._paused;
}
http://fiddle.jshell.net/6nhGW/
Test Code
var button = document.getElementById('extendTimeout'),
button2 = document.getElementById('tempChangeCallback'),
button3 = document.getElementById('changeCallback'),
button4 = document.getElementById('resetTimer'),
button5 = document.getElementById('pauseTimer'),
startTime,
timeout = -1;
var timer = new Timer(3000, function() {
console.log('Total time elapsed: ' + (new Date() - startTime));
startTime = null;
})
button.addEventListener('click', function() {
if (!startTime) startTime = new Date();
timer.callTimer();
})
button2.addEventListener('click', function() {
if (!startTime) startTime = new Date();
timer.callTimer(function() {
console.log('Temporarily change callback');
console.log('Total time elapsed: ' + (new Date() - startTime));
startTime = null;
});
})
button3.addEventListener('click', function() {
timer.changeCallback(function() {
console.log('Callback has been changed!');
startTime = null;
}, true);
});
button4.addEventListener('click', function() {
timer.resetTimer();
startTime = null;
});
button5.addEventListener('click', function() {
if (!startTime) startTime = new Date();
timer.pauseTimer();
});