Search code examples
javascriptphpjqueryajaxsettimeout

More than 1 ajax function being called at once, PHP, AJAX


I have a working ajax function that when called will display the current time, and then setTimeout for ten seconds before displaying the new time. I call this function when onkeyup is triggered on an text input, and it works. But there is a slight problem. If I type something else in the text input after the ajax function has already been called, it'll call another ajax function, and have two ajax functions running at the same time. For example:

If the first ajax function was called at 3:00:00 when it was triggered, and the second ajax function is called at 3:00:05, that means that there are now two ajax functions running at the same time. The first ajax function will be triggered again at 3:00:10, after the 10 second setTimeout, and the second ajax function will be triggered again at 3:00:15, after its 10 second setTimeout. So the more times you trigger the onkeyup in the text input, the more times the function will be called. I just want 1 function of itself to be running at the same time, not 2, 3, or more. How do I do that? Thanks.

ajax.php

<script type = "text/javascript"> 

function timeoutAjax(url,type,theName,id,timeout) {

      $.ajax({
           type: "POST",
           url: url,
           data: { select: $(type+'[name='+theName+']').val()},
           error: function(xhr,status,error){alert(error);},
           success:function(data) {
             document.getElementById( id ).innerHTML = data;
             setTimeout(function() { timeoutAjax(url,type,theName,id,timeout); }, timeout);
           }

      });

}

</script>

test1.php

<?php

include('ajax.php');

echo "<input type = 'text' name = 'name' onkeyup = 'timeoutAjax(\"test2.php\",\"input\",\"name\",\"output1\",\"10000\")'>";
echo "<div id = 'output1'/>";

?>

test2.php

<?php

$time = date('H:i:s A');
echo $time;

?>

************MORE DETAILS************

echo "<input type = 'submit' name = 'name1' value = 'Reset' onclick = 'timeoutAjax(\"test2.php\",\"input\",\"name1\",\"output1\",\"10000\")'>";
echo "<input type = 'submit' name = 'name2' value = 'Reset' onclick = 'timeoutAjax(\"test2.php\",\"input\",\"name2\",\"output2\",\"10000\")'>";

echo "<div id = 'output1'/>";
echo "<div id = 'output2'/>";

Solution

  • If I understand your question correctly, you actually trying to achieve two things here:

    1. Only the last ajax call

    After the last key stroke, do some ajax call. Any ajax call that is already busy can be skipped, you are just interested in the last one.

    This should not be to hard. jQuery returns an xhr object when you call the ajax function. On that xhr object, you can just call the abort() method to cancel a pending call. (Abort Ajax requests using jQuery)

    2. Repeat the ajax call every x time

    Right now you set a timeout in your ajax success function that will just repeat the call after a given time. Problem is that when you call your ajax function again from the outside (so not recursively I mean, but by another keystroke or something) you will just create another infinite string of ajax calls. After a while you'll end up with a huge queue of calls that will start to overlap and eat up all your resources.

    This can easily be solved by storing the result of that setTimeout in a variable, and calling clearTimeout on that variable each time before you set a new timeout. This way you cancel the old 'queue' and just start a new one.

    So enough poor english, let's try to show what I mean by updating your code:

    function timeoutAjax(url, type, theName, id, timeout, trigger) {
        // abort pending calls
        if (trigger.xhr) {
            trigger.xhr.abort();
        }
        // abort queued calls
        clearTimeout(trigger.queued);
    
        // make the call
        trigger.xhr = $.ajax({
            type: "POST",
            url: url,
            data: {
                select: $(type + '[name=' + theName + ']').val()
            },
            error: function (xhr, status, error) {
                alert(error);
            },
            success: function (data) {
                document.getElementById(id).innerHTML = data;
                // queue a new call
                trigger.queued = setTimeout(function () {
                    timeoutAjax(url, type, theName, id, timeout, trigger);
                }, timeout);
            }
    
        });
    
    }
    

    Just one more sidenote. Even with the changes I made to your code, you will be aborting and making a new ajax call on every key stroke. And aborting an ajax call does not automatically mean your server stops handling the request, depnding on what backend you are using. For the simple php script you are using now it is probably fine, but still, it is probably better to wait until the user is done with typing before you make your first call. This is called Debouncing and isn't very hard to implement either: http://davidwalsh.name/javascript-debounce-function