php - Javascript: why is my instant search function running lagging, how to improve?

673

The demo below is the instant search function I build, just like google search, printing out result right after the user's input.

When testing, it runs smoothly on localhost, but on the web, it runs lagging, that is, when user typing in multiple characters fast, the keypress will not show in input box for some seconds to wait for data processing (I guess) then the charactered typed showed many seconds after . Absolutely this is no good for user's experience. How may I resolve this?

Frontend

<input onkeyup="searchq();" type="text">
<script>
function searchq(){
        // get the value
            txt = $("input").val();
            // post the value
            if(txt){
                $.post("search.php", {searchVal: txt}, function(result){
                    $("#search_output").html(result+"<br><a class='anchor_tag_s' href='createobject.php?object="+txt+"'><div id='notfound'>Not found above? Create Here.</div><a>");
                });
            }
            else{
                $("#search_output").html("");
            }
        };
</script>

Backend

    //query the search using match
    $query=mysqli_query($conn,"SELECT * from objects WHERE Match(name) Against ('%$search%' in natural language mode) LIMIT 9") or die("could not search! Oops, Panpan might be hacked");
    $count=mysqli_num_rows($query);
   //if match no result using like query
    if($count==0){
        $query=mysqli_query($conn,"SELECT * from objects WHERE name LIKE '%$search%' LIMIT 9") or die("could not search! Oops, Panpan database might be hacked");
        $count=mysqli_num_rows($query);
        if ($count==0){
            while($count==0){

            //if matach and like show no result, remove the frist word of array, then search, if no result, do it again, if not, do it again.
                $search = explode(" ",$search);
                $search=array_slice($search,1,2);
                $search=implode(" ",$search);
                $query=mysqli_query($conn,"SELECT * from objects WHERE name LIKE '%$search%' LIMIT 9") or die("could not search! Oops, Panpan database might be hacked");
                $count=mysqli_num_rows($query);
                while($row=mysqli_fetch_assoc($query)){
                $object_id=$row["object_id"];
                $object_name=$row["name"];
                $object_description=$row["description"];
                $object_up=$row["up"];
                $object_down=$row["down"];
                $object_views=$row["views"];

                $output=$object_name;
                $result= "<a class='anchor_tag_s' href='"."object.php?id=".$object_id."'><div>".$output."</div></a>";
                echo $result;
                }
            }
        }   
        else{
             // print out the like query
            while($row=mysqli_fetch_assoc($query)){
            $object_id=$row["object_id"];
            $object_name=$row["name"];
            $object_description=$row["description"];
            $object_up=$row["up"];
            $object_down=$row["down"];
            $object_views=$row["views"];

            $output=$object_name;
            $result= "<a class='anchor_tag_s' href='"."object.php?id=".$object_id."'><div>".$output."</div></a>";
            echo $result;
            }
        }
    }
    else{
          // print out the match query
        while($row=mysqli_fetch_assoc($query)){
            $object_id=$row["object_id"];
            $object_name=$row["name"];
            $object_description=$row["description"];
            $object_up=$row["up"];
            $object_down=$row["down"];
            $object_views=$row["views"];

            $output=$object_name;
            $result= "<a class='anchor_tag_s' href='"."object.php?id=".$object_id."'><div>".$output."</div></a>";
            echo $result;
        }
    }

}


?>
49

Answer

Solution:

I'd suggest absolutely not searching directly on key-up. That's incredibly inefficient and very resource intense. I'd suggest setting a timer for say, one second. Then, on key-up, you refresh that timer to one second. If it ever reaches 0, then you search. Something like this:

timer = 1000;
started = false;

$("input[type=text]").keyup( function(){
    window.timer = 1000;

    if(window.started == false) queueTimer();
    window.started = true;
});

function queueTimer(){
    if(window.timer <= 0){
        //Timer has run out, business logic here!
        searchq();
        window.started = false;
    } else {
        window.timer -= 100;

        setTimeout(queueTimer, 100);
    }
}

Set the timer to whatever you want, in milliseconds. I recommend one second, but you can lower it as you see fit.

Check the fiddle here:

https://jsfiddle.net/kbyy2m6u/

What the code is doing

Right off the bat, we set our timer to 1000 milliseconds andstarted tofalse.

Thekeyup inline-function is resetting the timer to 1000 milliseconds, queues the timer, and setsstarted totrue. We set it totrue so thequeueTimer() function does not get queued multiple times (which would negate the entire point of queueing instant searches). Once it's set totrue, it will not runqueueTimer() until the timer runs out and a search is actually conducted.

queueTimer() is the bread and butter here. If the timer has not run out yet, it will simply decrease thetimer variable by 100 milliseconds, and call itself to be ran again in 100 milliseconds (looping until the timer runs out). Once it runs out, it executes yoursearchq() and setsstarted tofalse again so the instant search can run once more.

In plain English, every time someone types in a search box it will wait one second before doing an instant-search. The timer will reset on key-up, even after the queue is started, so that while typing a person will not be searching. This prevents multiple erroneous searches by making sure a user has paused for a bit to actually conduct a search.

Now a word of caution

Google is a giant - they make magical things happen on the web. Things like an instant search are great in theory, but for those of us who aren't able to throw billions of dollars at R&D like Google, it's something that's not typically worth the headache.

Every single call you make to the database is taxing. If you've got other functionality on your web application that hits the DB and now you're adding an instant search, be prepared for some pretty interesting side-effects. They may even be unforeseen side effects on totally separate databases due to data locks on your MySQL Engine. This is one reason why Data Locking is so prevalent in a lot of Magento installs.

I'm sure you know what you're doing, but I want to make sure anyone who sees this question will realize the trade-off to something like instant search.

148

Answer

Solution:

You should consider two things: debounce your calls and abort any previous ajax requests.

For the first one, there are lots of information on debounce/throttle techniques. Basically you have to assure that you do not execute more than one function call (searchq) in a certain period of time. Thus, if the user typesabc, it won't trigger 3 different searches fora,ab andabc. Instead, it will trigger a single search for the whole result (abc).

Another thing you should consider is aborting unresolved ajax calls.
Since you're relying on ajax calls to show results, and since ajax calls are... well... asynchronous, you shouldn't actually have multiple simultaneous ajax calls. Take the following example:

  1. the user typesab
  2. thesearchq function is executed for the first character (a)
  3. thesearchq function is executed for the new sequence (ab)
  4. the ajax promise for the second call gets resolved
  5. the ajax promise for the first call gets resolved
  6. the user sees the result for the wrong input

To avoid this issue, you should abort - or ignore at least - any other ajax call that is in progress by the time you fire a new one.

People are also looking for solutions to the problem: get.php config to read and delete line from a file.txt

Source

Didn't find the answer?

Our community is visited by hundreds of web development professionals every day. Ask your question and get a quick answer for free.

Ask a Question

Write quick answer

Do you know the answer to this question? Write a quick response to it. With your help, we will make our community stronger.

Similar questions

Find the answer in similar questions on our website.