0

I'm trying to implement a search bar like facebook for my website users. While you type the name, some results are displayed. To avoid sending a request for each button pressed, i've setup a timeout. The idea is: if i'm going to type jack It doesn't make sense to search for j, ja, jac, jack, but it's better to wait for the users finishes typing before sending any request. Once the request is sent and completes, a div called mydiv is filed with results (the request response). If after some time long enough i type another letter, another request is sent and mydiv is filled with new results.

The idea comes from this question. Here is my simplified implementation.

var thread = null;    

$('#search-user').keyup(function() {
  clearTimeout(thread);
  name = $('this').val(); //i get the name just typed
  thread = setTimeout(function(){ 
    get_data_with_ajax_and_put_it_in_mydiv(name);
  }, 200);              
});

function get_data_with_ajax_and_put_it_in_mydiv(name){
  $.post()....
  /*Do some stuff*/
}

As you can see, after a 200ms timeout the function get_data_with_ajax_and_put_it_in_mydiv(); is called. This function, emptys mydiv before putting new data. It works almost always, but sometimes a strange bug occurs.

I'm going to explain where i think the problem is, by providing a real example. Let us assume that get_data_with_ajax_and_put_it_in_mydiv() takes from 50ms to 1000ms to complete, depending on various factors (network speed, congestion, etc...).

  • At t=0 i type jac and i stop typing.
  • At t=200 the timeout expires and get_data_with_ajax_and_put_it_in_mydiv() runs. In this case it takes 1000ms to run
  • At t=210, because i'm a slow writer, i type the letter k of jack. mydiv is empty because the first request has not yet completed.
  • At t=410 the timeout for the letter k epires and a second request is sent. This time, the function takes 100ms to run.
  • At t=510 the second request finishes and i get the results for jack.
  • At t=1200 the first request finishes and i get the results for jac.

ERROR

As you can see due to impredictability of time elaped by ajax requests i got a wrong result. mydiv is filled with jac results and not jack.

SOLUTION

The first solution that came to my mind is the following: every time i call get_data_with_ajax_and_put_it_in_mydiv() i have to stop any previous request still running. How can i do that? If not possible, how can i fix this error?

Community
  • 1
  • 1
Alberto Fontana
  • 928
  • 1
  • 14
  • 35
  • 3
    Aborting previous requests sounds like a good idea. Here is how to abort an Ajax request: http://stackoverflow.com/a/446626/678801 – Christofer Eliasson Jan 07 '14 at 19:53
  • 2
    Quick and dirty solution would be to include the search string in your returned results and compare it to the last search string you sent. If it's not the same, just ignore the results. – Matt Burland Jan 07 '14 at 19:53
  • Try sending a timestamp to the request and return the same timestamp. You store this timestamp in a global var and update it each request. When a request is complete, before you update the div content, check if the timestamp is the same of the request. You'll have always the last request result on the div. – DontVoteMeDown Jan 07 '14 at 19:53
  • You can also abort the request as @ChristoferEliasson suggested, but there's still a chance that you might abort it just a fraction too late. – Matt Burland Jan 07 '14 at 19:58
  • I did as Christofer Eliasson suggested and it seems working...tried 50 times and no error, while previously i got error like 4-5 times. @MattBurland what do u mean? – Alberto Fontana Jan 07 '14 at 20:03
  • It's probably rare, but it's possible that you might try to abort a request right after it completed anyway. Running it 50 times, it'll probably not happen, but put it in production and have it running millions of times and it might well pop up sporadically. Because of that, I'd either return the original request with your data or timestamp as @DontVoteMeDown suggested just for a sanity check. I wouldn't rely only on the timing of an abort always taking care of it. Also remember that an abort won't stop the server from processing the request. if it's already got it. – Matt Burland Jan 07 '14 at 20:37
  • @MattBurland you're right. Personally, I preffer receive and ignore *no-more-important-requests* than manage them and cancel etc because of performance. As you said, it will not prevent server to proccess and it will be frequent cancel and already received request. – DontVoteMeDown Jan 07 '14 at 22:31

2 Answers2

0

Why not use a debounced function to handle the ajax call?

http://benalman.com/code/projects/jquery-throttle-debounce/examples/debounce/

Michael Benin
  • 4,317
  • 2
  • 23
  • 15
0

You should use the Promise interface and use the 'done' method to chain these two operations sequentially

http://api.jquery.com/jquery.post/

Glenn Ferrie
  • 10,290
  • 3
  • 42
  • 73
  • 1
    This is an option, but in this particular case it seems unnecessary. If a response for `jack` has already been received, nobody cares about the result from the request for `jac` so why waste time waiting for it to finish? In other scenarios where the later request doesn't completely supersede the earlier one, this would be the way to handle it. – Matt Burland Jan 08 '14 at 03:59