3
\$\begingroup\$

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.

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();
}
<button id="btn">Foo</button>

200_success
146k22 gold badges190 silver badges478 bronze badges
asked Jan 1, 2015 at 6:05
\$\endgroup\$

1 Answer 1

4
\$\begingroup\$

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:

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
});
answered Jan 1, 2015 at 18:18
\$\endgroup\$
1
  • \$\begingroup\$ Wow how do you learn all of these. Did you take any inspiration of this implementation from somewhere? \$\endgroup\$ Commented Sep 7, 2017 at 3:00

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.