views:

688

answers:

3

Hiya All,

I've created a Facebook style ajax search for my site where as you type it will bring up the results in a nice list below your search.

$("#s").keyup(function() {
    var searchbox = $(this).val();
    var dataString = 's='+ searchbox;
    if(searchbox!='') {
     $.ajax({
      type: "POST",
      url: "/livesearch.php",
      data: dataString,
      cache: false,
      success: function(html){
       $("#display").html(html).show();
      }
     });
    } else {return false; }  
});

$("body").click(function() {
  $("#display").hide();
});

The problem with this is it's a little ineffective as the user will type a word for example "football". This will carry out 8 requests to the server. What would be a more effective way to do this? ideally i think it should store the request for 1 second before doing a search rather than instant keyup. but not 100% sure how to do that...

+2  A: 

Another option would be to start searching after 2/3 characters. Waiting for 1 second before making every request doesn't look good to me. Also try to send very less data back to server which might also make the request and response faster.

Shoban
Do you have a code example?
Shadi Almosri
pseudocode: var prevChars; if (prevChars.length + 3 <= chars.length) { debounce(...); prevChars = chars; }
Piskvor
+2  A: 

You could have a JSON object sitting somewhere and searching that instead of searching the database multiple times. It won't bring too much overhang, as long as it's not a list of 1,000 friends or something.

Garrett
Good point - pre-fetch the most-searched for items (if applicable), search only if cache miss
Piskvor
+6  A: 

the method you are referring to is called "Debouncing"

I usually have a "Debounce" function at the bottom of all my scripts

var debounce=function(func, threshold, execAsap) {
    var timeout;
    return function debounced () {
        var obj = this, args = arguments;
        function delayed () {
            if (!execAsap)
                func.apply(obj, args);
            timeout = null; 
        };
        if (timeout)
            clearTimeout(timeout);
        else if (execAsap)
            func.apply(obj, args);
        timeout = setTimeout(delayed, threshold || 100); 
    }; 
};

And then whenever I do anything that will benefit from a debounce I can use it generically

So your code would be re-written as

$("#s").keyup(debounce(function() {
    var searchbox = $(this).val();
    var dataString = 's='+ searchbox;
    if(searchbox!='') {
        $.ajax({
                type: "POST",
                url: "/livesearch.php",
                data: dataString,
                cache: false,
                success: function(html){
                        $("#display").html(html).show();
                }
        });
    } else {return false; }  
}
,350 /*determines the delay in ms*/
,false /*should it execute on first keyup event, 
       or delay the first event until 
       the value in ms specified above*/
));
pǝlɐɥʞ
of course, you can play around with the delay value to find out what suits you best, for me 350m/s works perfectly....remember, people type quite fast, and the timeout gets reset to 350ms everytime a letter is typed
pǝlɐɥʞ
Also, I suggest caching the results, either in JS or w/ HTTP - example: `deboun[500 ms pause]cws[1000 ms pause][backspace][backspace][backspace][500 ms pause]ce`. Without caching, you're sending 2 requests for `deboun`.
Piskvor
Works great! Thanks!
TaylorOtwell