Speeding Up Interaction by Cancelling Events

by Michael

At my last project (I’m an IT-Consultant), I was helping fine-tune as well as bug fix the customers JavaScript based map application. One feature of the map application was that the user could interact with the map, i.e., pan around as well as zoom in, which would then trigger a search inside the given bounding box. A search executes an Ajax REST call to the search service, which can take up to around 500ms to respond, depending on the search criteria as well as the number of results found.

The problem was that several searches could be queued within just a few milliseconds, thus resulting in several searches being executed back-to-back each taking around a half second to complete. Very frustrating for the user. Solving this problem proved to be quite easy – fact of the matter is that only the last search is of importance to the user, within a given time frame – say 300ms. This led to the implementation of a cancelling queue or what I call a null queue, i.e., all searches that are queued within less than 300ms of each other are subject to being cancelled, only the last search in the queue will be executed. This is a lot like a timeout for autocomplete.

/**
 * Instantiate a NullQueue and set the threshold timeout value
 * to be used for nulling items in the queue.
 * 
 * @constructor
 * @param {Integer} threshold The timeout value
 */
function NullQueue(threshold) {
 
    this.threshold = threshold;
    this.queue = [];
    this.timerId = null;
 
}

/**
 * Push an item on to the queue. 
 * 
 * Every time an item is pushed on to the queue, the 
 * timeout is reset.
 * 
 * @param {Function} item Item to execute
 */
NullQueue.prototype.push = function(item){
 
    var me = this;
 
    me.queue.push(item);
 
    if (null !== me.timerId) {
        clearTimeout(me.timerId);
    }
 
    me.timerId = setTimeout(function(){
        me.process();
    }, me.threshold);
};


/**
 * Process the queue.
 * 
 * All items, except for the last item in the queue
 * are nulled. The last item is then executed.
 * 
 * @private
 */
NullQueue.prototype.process = function() {
 
    var me = this;
 
    var item = me.queue[me.queue.length - 1];
    me.queue = [];
 
    item.call();
};



/**
 * Test the NullQueue implementation
 * 
 * Move the mouse around inside the browser. Your current cursor
 * coordinates will be shown in an alert when you hold the cursor
 * still for 500ms.
 * 
 * @test
 */
function testNullQueue(){

    var testQueue = new NullQueue(500);
 
    document.addEventListener("mousemove", function(ev){
 
        testQueue.push(function(){
              alert("Mouse: x=" + ev.pageX + ", y=" + ev.pageY);
        });
  
    }, false);
}

testNullQueue();
Advertisements