patternjavascriptMinor
Inactivity Timeout
Viewed 0 times
timeoutinactivitystackoverflow
Problem
I made this piece of code to detect inactivity on different aspects of my app. It is part of a set of pieces to analyze user behavior.
Not saying it's ugly, but good looking constructive criticism to help me improve my code and could be useful to me for other similar components.
Not saying it's ugly, but good looking constructive criticism to help me improve my code and could be useful to me for other similar components.
function InactivityTimeout(idle_time, callback) {
this.state = 0; // 0-new, 1=active, 2=idle
this.idle_time = idle_time;
this.callback = callback;
this.start();
}
InactivityTimeout.prototype.start = function() {
this.state = 1;
this.timer = setTimeout(this.timeout.bind(this), this.idle_time);
}
InactivityTimeout.prototype.activity = function() {
if (this.state == 1) {
clearTimeout(this.timer);
}
this.start();
}
InactivityTimeout.prototype.timeout = function() {
this.state = 2;
this.callback();
}
/// usage
var timer=new InactivityTimeout(5000, function() {
alert("idle reached");
});
var el = document.getElementById('btn');
el.onclick = function() {
timer.activity();
}
FooSolution
You could pass in an object into the constructor instead of using arguments. That way, you don't have to mind order. Additionally, you could add in defaults:
Now you wouldn't want to make this code run all the time, so I suggest you add in a
You wouldn't want to hard-code all the code that runs when activity or inactivity occurs. I suggest you extend from an EventEmitter object. I have a simple implementation of such, which you could just plug in. Now you emit events in your code, and code outside can listen.
The same with listening for events instead of hard-coding the code that reacts to the events into
function InactivityTimer(options){
// Defaults
this.defaults = {
timeout : 10
};
// Merge options to defaults> Let's just say you use jQuery.
this.options = $.extend({}, this.defaults, this.options);
}Now you wouldn't want to make this code run all the time, so I suggest you add in a
start as well as a stop. You could also add in an autostart in options so it starts as soon as an instance is created.InactivityTimer.prototype.start = function(){
if(this.timer) return;
this.timer = setTimeout(function(){
...
},this.options.timeout);
}
InactivityTimer.prototype.stop = function(){
clearTimeout(this.timer);
this.timer = null;
}You wouldn't want to hard-code all the code that runs when activity or inactivity occurs. I suggest you extend from an EventEmitter object. I have a simple implementation of such, which you could just plug in. Now you emit events in your code, and code outside can listen.
function InactivityTimer(options){
EventEmitter.call(this); // Inherit properties
...
}
InactivityTimer.prototype = new EventEmitter();
InactivityTimer.prototype.start = function(){
if(this.timer) return;
this.timer = setTimeout(function(){
this.emit('idle');
},this.options.timeout);
this.emit('start');
}
InactivityTimer.prototype.stop = function(){
clearTimeout(this.timer);
this.timer = null;
this.emit('stop');
}
var idleCheck = new InactivityTimer({...});
idleCheck.on('start',function(){
// timer started
});
idleCheck.on('stop',function(){
// timer stopped
});
idleCheck.on('idle',function(){
// user became idle
});
idleCheck.on('active',function(){
// user became active
});The same with listening for events instead of hard-coding the code that reacts to the events into
InactivityTimer, you'd might want to also extract the code that listens for activity. Activity can be anything, and the consumer of your code might consider only click or probably mouse movement etc. Suggesting you add observe to listen for certain activity.InactivityTimer.prototype.observe = function(observer){
var instance = this;
// Call the observer, passing it a callback that should be called when an event happens
observer.call(this, function(){
clearTimeout(instance.timer); // clear the timer
instance.emit('active'); // inform listeners that timer became active
instance.start // start another timer
});
});
// Usage
var timer = new InactivityTimer({...});
timer.observe(function(activate){
$('body').on('click',activate); // Observe body clicks
$(window).on('scroll',activate); // Observe scrolling
});Code Snippets
function InactivityTimer(options){
// Defaults
this.defaults = {
timeout : 10
};
// Merge options to defaults> Let's just say you use jQuery.
this.options = $.extend({}, this.defaults, this.options);
}InactivityTimer.prototype.start = function(){
if(this.timer) return;
this.timer = setTimeout(function(){
...
},this.options.timeout);
}
InactivityTimer.prototype.stop = function(){
clearTimeout(this.timer);
this.timer = null;
}function InactivityTimer(options){
EventEmitter.call(this); // Inherit properties
...
}
InactivityTimer.prototype = new EventEmitter();
InactivityTimer.prototype.start = function(){
if(this.timer) return;
this.timer = setTimeout(function(){
this.emit('idle');
},this.options.timeout);
this.emit('start');
}
InactivityTimer.prototype.stop = function(){
clearTimeout(this.timer);
this.timer = null;
this.emit('stop');
}
var idleCheck = new InactivityTimer({...});
idleCheck.on('start',function(){
// timer started
});
idleCheck.on('stop',function(){
// timer stopped
});
idleCheck.on('idle',function(){
// user became idle
});
idleCheck.on('active',function(){
// user became active
});InactivityTimer.prototype.observe = function(observer){
var instance = this;
// Call the observer, passing it a callback that should be called when an event happens
observer.call(this, function(){
clearTimeout(instance.timer); // clear the timer
instance.emit('active'); // inform listeners that timer became active
instance.start // start another timer
});
});
// Usage
var timer = new InactivityTimer({...});
timer.observe(function(activate){
$('body').on('click',activate); // Observe body clicks
$(window).on('scroll',activate); // Observe scrolling
});Context
StackExchange Code Review Q#75407, answer score: 4
Revisions (0)
No revisions yet.