40

Possible Duplicate:
Kill Ajax requests using JavaScript using jQuery

Here is the simple code I am working with:

$("#friend_search").keyup(function() {

    if($(this).val().length > 0) {
        obtainFriendlist($(this).val());
    } else {
        obtainFriendlist("");
    }

});

function obtainFriendlist(strseg) {

    $.ajax({
       type: "GET",
       url: "getFriendlist.php",
       data: "search="+strseg,
       success: function(msg){
        UIDisplayFriends(msg);
       }
     });
}

Essentially, if a keyup event is fired before the function obtainFriendlist returns a result (and triggers UIDisplayFriends(msg), I need to cancel the in-flight request. The issue I have been having is that they build up, and then suddenly the function UIDisplayFriends is fired repeatedly.

Thank you very much, and advice is helpful too

0

2 Answers 2

24

The return value of $.ajax is an XHR object that you can call actions on. To abort the function you would do something like:

var xhr = $.ajax(...)
...
xhr.abort()

It may be smart to add some debouncing as well to ease the load on the server. The following will only send an XHR call only after the user has stopped typing for 100ms.

var delay = 100,
    handle = null;

$("#friend_search").keyup(function() {
    var that = this;
    clearTimeout(handle);
    handle = setTimeout(function() {
        if($(that).val().length > 0) {
            obtainFriendlist($(that).val());
        } else {
            obtainFriendlist("");
        }
    }, delay);
});

A third thing that you should really be doing is filtering the XHR responses based on whether or not the request is still valid:

var lastXHR, lastStrseg;

function obtainFriendlist(strseg) {
    // Kill the last XHR request if it still exists.
    lastXHR && lastXHR.abort && lastXHR.abort();

    lastStrseg = strseg;
    lastXHR = $.ajax({
       type: "GET",
       url: "getFriendlist.php",
       data: "search="+strseg,
       success: function(msg){

        // Only display friends if the search is the last search.
        if(lastStrseg == strseg) 
          UIDisplayFriends(msg);
       }
     });
}
3
  • 1
    I like what you do with the delay, that's nice. However, isn't there still a risk that the requests pile up if the user is a slow writer, triggering a new ajax-request with every keystroke? Commented Nov 5, 2011 at 23:14
  • 1
    It would still be a risk, so you would want to apply both strategies, cancelling the old query and the above method for reducing server calls. A third screen would be validating that the output still matches the request. Commented Nov 6, 2011 at 0:37
  • 1
    Excellent. thank you, this is very informative
    – TaylorMac
    Commented Nov 6, 2011 at 2:44
0

How about using a variable, say isLoading, that you set to true through using the beforeSend(jqXHR, settings) option for .ajax, and then using the complete setting to set the variable back to false. Then you just validate against that variable before you trigger another ajax call?

var isLoading = false;
$("#friend_search").keyup(function() {

    if (!isLoading) {
       if($(this).val().length > 0) {
           obtainFriendlist($(this).val());
       } else {
           obtainFriendlist("");
       }
    }

});

function obtainFriendlist(strseg) {

    $.ajax({
       type: "GET",
       url: "getFriendlist.php",
       beforeSend: function () { isLoading = true; },
       data: "search="+strseg,
       success: function(msg){
        UIDisplayFriends(msg);
       },
       complete: function() { isLoading = false; }
     });
}
1
  • 1
    Wouldn't this be the opposite? If the user types "TEST" before the XHR returns, the keypresses for E, S, and T would be ignored and the server response would be only for "T". Commented Nov 6, 2011 at 0:45

Not the answer you're looking for? Browse other questions tagged or ask your own question.