2

i have this event on keydown:

$.post("search.php", { s: $('#box_s').val()},
               function(data) {
                  /**/
               }
});

the problem is that as many keydown as many requests and sometimes older requests override recent requests results

so i would need to

$('input#box_s').keydown(function(){
     abort_previous_post();
     $.post("search.php", { s: $('#box_s').val()},
                   function(data) {
                      /**/
                   }
    });
});

is that posible?

Toni Michel Caubet
  • 19,333
  • 56
  • 202
  • 378
  • similar to this: http://stackoverflow.com/questions/1434519/can-you-cancel-a-jquery-ajax-call-before-it-returns and this http://stackoverflow.com/questions/446594/kill-ajax-requests-using-javascript-using-jquery – Joseph Jan 29 '12 at 04:20

4 Answers4

3

You can throttle it so that a request is not made until the user has stopped typing for x milliseconds. 250-400ms seems a good value:

function throttle( fn, time ) {
    var timer = 0;

    return function() {
        window.clearTimeout( timer );
        var self = this,
            args = [].slice.call( arguments );


        timer = setTimeout( function() {
            return fn.apply( self, args );
        }, time );
    };

}

And usage:

$('input#box_s').keydown( throttle( function(){

     $.post("search.php", { s: $('#box_s').val()},
                   function(data) {
                      /**/
                   }
    });
}, 400 ) );

In this case a request is made after the user starts typing and then stops for 400ms.

Esailija
  • 138,174
  • 23
  • 272
  • 326
  • what if the client doesn't receive response in 400 ms? it will override the most recent. – meze Jan 29 '12 at 04:24
  • @meze it depends on use case, auto-suggest is pretty useless for example if it takes more than 400ms. Google has autosuggest on 100ms and instant on 1000ms. – Esailija Jan 29 '12 at 04:28
  • Nice generic throttling implementation! You could potentially have another one specific for fetches (e.g. throttleFetch) that could also handle the cancellation or invalidation of the previous fetch. – Ates Goral Jan 29 '12 at 04:35
  • @Esailija How do you know 1000ms on instant? I type a 4 letters word and it does 4 queries in a row. – meze Jan 29 '12 at 04:36
  • @meze I see `setTimeout` called with 1000 as argument for time and approx 1 second later the result appears. You could dig in with breakpoints but it's a mess with obfuscated code. – Esailija Jan 29 '12 at 04:45
  • @Esailija if you "hook" in `XMLHttpRequest.send`, you'll see requests are sent immediately. The result appears after 1 second because of latency. – meze Jan 29 '12 at 05:10
  • @meze you are probably right, I thought those were for the suggestions but there doesn't appear any separate request for instants. They are also sending a lot of markup as well instead of just data. – Esailija Jan 29 '12 at 05:17
0

I'd approach it something like this:

var requestCount = 0;

$('input#box_s').keydown(function(){
     requestCount++;
     var thisRequestCount = requestCount;
     $.post("search.php", { ingredientes_s: $('#box_s').val()},
                   function(data) {
                      if(thisRequestCount!=requestCount) return;
                      /**/
                   }
    });
});
  • This makes a whole bunch of unnecessary requests to the server. The more users you have or the larger datasets you have, this really becomes an unacceptable solution. – Alec Gorge Jan 29 '12 at 04:23
  • @alecgorge google live search doesn't have any timeouts and they have many users. They are fine ;) – meze Jan 29 '12 at 04:27
  • Submitting a request doesn't imply high bandwidth. It might cost an extra 400 bytes per second if you don't throttle a simple query. More complex ones, there very well could be a problem.. but the question implies just what was typed is being sent. –  Jan 29 '12 at 04:30
  • Google has spent considerable time, money and effort to make search results come in as quickly as possible. For most developers, we are talking about a FULLTEXT or LIKE query against a MySQL database. Minimizing hits on the server, on PHP and on MySQL is a wise idea--especially when the end result is very similar. – Alec Gorge Jan 29 '12 at 04:32
  • @alecgorge I didn't say it's better, it was to "this really becomes an unacceptable solution." – meze Jan 29 '12 at 04:40
  • Good point: processing the request might cost a lot more server-side than is apparent from looking at the client. I'm still leaving my answer as is, because it answers the question as it was asked. –  Jan 29 '12 at 04:41
  • But it does become high bandwidth because the requests aren't canceled. They are still processed, just nothing is done with the data. If I type in something like "this is a really long search term", the browser will make a request, the server will have to process and the browser will download results for "t", "th", "thi", "this", etc. That is high bandwidth and high load on the server. – Alec Gorge Jan 29 '12 at 04:42
  • you really are making a lot of assumptions about what the server is doing, but I don't think that's justified. If i was trying to make something similar to live search, I'd limit the results to maybe 10 items. The response would be maybe a kilobyte. With multi-megabyte pages these days, that's nothing. –  Jan 29 '12 at 04:44
0

What you want to do is not start the request unless there has been a slight delay:

var timeoutID;
$('#box_s').keydown(function () {
    clearTimeout(timeoutID);
    timeoutID = setTimeout(function () {
        $.post("search.php", { ingredientes_s: $('#box_s').val()}, function(data) {
            /** **/
        });
     }, 500);
});

Check this jsFiddle for a demo.

Alec Gorge
  • 17,110
  • 10
  • 59
  • 71
  • This doesn't answer the original question, which was, how do you abort the request? – PriorityMark Jan 29 '12 at 04:25
  • Correct, but this is a better solution for what he is trying to do. Aborting the request is a common way of thinking about it, but it is incredibly inefficient and should not be done. – Alec Gorge Jan 29 '12 at 04:26
0

The post call is just a convince method for the Ajax handler, so capture the xhr, and abort it.

var jqxhr;

$('input#box_s').keydown(function(){
     if (jqxhr) jqxhr.abort();
     $.post("search.php", { ingredientes_s: $('#box_s').val()},
                   function(data) {
                      /**/
                   }
    });
});
PriorityMark
  • 3,247
  • 16
  • 22