I was tackling a problem the other day related to triggering ajax requests as a user was typing in an input field. Sometimes you can just fire off the request on the blur event, but other times you want to fire it off from a keypress event. Sending xhr requests on every keypress can quickly overload your server and/or database. More often than not, if a user is typing, you can wait until they are done, or for a pause in their button mashing to send the request. This saves your server from getting hammered by un-needed requests, but still gives the user the experience desired.
A simple approach to this is wrapping your method that handles the particular ajax request with another simple method that records the time when they key was pressed, and queues up the ajax request method using setTimeout. Here’s an example below:
Example = {
interval : 1000,
lastKeypress : null,
interceptKeypress : function() {
this.lastKeypress = new Date().getTime();
var that = this;
setTimeout(function() {
var currentTime = new Date().getTime();
if(currentTime - that.lastKeypress > that.interval) {
that.sendRequest();
}
}, that.interval + 100);
},
sendRequest : function() {
//Perform xhr request
}
}
The Example.interceptKeypress() method now becomes what you tie the keyup event of your text input to instead of going straight to the Example.sendRequest() method. The current time is recorded, and then Example.sendRequest() is queued up using setTimeout() and a closure to handle scoping and ensure that enough time has passed since the last keyup event (100 ms is added to the current time as a buffer).
This approach can easily be added onto existing event handlers if you find you’re sending too many requests in particular situations, or for any type of event handling where you want to limit when/how often it is fired. Hope this benefits some people!
9 Comments
Thanks for the code! I’ve been trying to do something like this for a while.
FYI. there is a small typo in your code. The second Date().getTime() is typed Date.getTime().
Again.. Thanks for the code.
Ah, so it is. Fixed now, thanks.
w00t just what I needed thanks
I’m having much more success without the 100 ms interval on the setTimeout. Placed an alert() in the sendResponse for testing. With the buffer, I’m seeing multiple alert fires where I should not, however seems to work fine without that buffer. Any insight?
I believe the buffer was needed only for a specific version of IE, maybe 6.5, but I don’t recall exactly. I can’t imagine why adding 100 ms to the timeout callback would cause multiple events to be fired. What event are you binding your callback to, the keyup?
On a related note, I have found that an additional feature is needed to ensure xhr callbacks are processed in the correct order. A local counter is needed on the object that increments every time your “interceptKeypress” is fired. Then when you call the xhr request function, you have to pass the current value of that counter, and then check it in the xhr callback to ensure what is passed in is the same as the current value of the counter. Without this I was seeing issues where the most recent xhr request would fire, get called back, and then a previously called request would come back afterwards and trump it.
Great, it solves my problem.
Thanks
As I smashed my head against the wall for the better part of an hour, I finally landed on the exact answer I needed. Brilliant.
I was implementing something similar in jQuery, but these days i’m finding excuses to use a delay before ajax in most of the UI stuff i do.
I packaged this up into a plugin available here for jquery that can be used with the normal $.ajax calls.
Old solution to old problems in new projects. Great code!!