简体   繁体   中英

Use setTimeout to periodically make autocomplete AJAX calls?

I would like to use a setTimeout function so that Ajax calls are only made at the most every 1 second.

Here is what I have. This is clearly not correct, but I am not sure how the setTimeout function works.

function autoComplete(q, succ)
{

    setTimeout(

    if(q != "") {
        $.ajax({type:"GET",
            url: "php/search.php",
            data: "q="+q,
            success: succ
        });
    }

    , 1000);
}

I think that I should use clearTimeout so that if another call is made, it will reset the timer and wait another 1 second, but when I tried to implement this it stopped running the function.

Pass a ... function :)

Using an anonymous function might be as follows:

var timeoutId
function autoComplete(q, succ)
{
    if (q) {
        // stop previous timeouts
        clearTimeout(timeoutId)
        timeoutId = setTimeout(function () {
            $.ajax({type:"GET",
                url: "php/search.php",
                data: "q="+q,
                success: succ
            });
         }, 1000);
    }
}

Note I move the check for q outside. This won't run two timeouts at once, but there may be multiple in-flight requests . To guard against this, the success callback needs a guard -- and a simple way to do this is with a counter. Checking the "current q" with the q in the setTimeout may lead to subtle race conditions.

var timeoutId
var counter = 0
function autoComplete(q, succ)
{
    if (q) {
        // Increment counter to maintain separate versions
        counter++
        var thisCounter = counter
        clearTimeout(timeoutId)
        timeoutId = setTimeout(function () {
            $.ajax({type:"GET",
                url: "php/search.php",
                data: "q="+q,
                success: function () {
                    // Only call success if this is the "latest"
                    if (counter == thisCounter) {
                       succ.apply(this, arguments)
                    }
                },
            });
         }, 1000);
    }
}

A smarter version might read the current value at time of submission because the above code will always lag one second behind...

Now, imagine getQ is a function object...

var timeoutId
var counter = 0
function autoComplete(getQ, succ)
{
    counter++
    var thisCounter = counter
    clearTimeout(timeoutId)
    timeoutId = setTimeout(function () {
        var q = getQ() // get the q ... NOW
        if (q) {
            $.ajax({type:"GET",
                url: "php/search.php",
                data: "q="+q,
                success: function () {
                    if (counter == thisCounter) {
                       succ.apply(this, arguments)
                    }
                },
            });
         }
     }, 1000);
}

// example usage
autoComplete(function () { return $(elm).val() }, successCallback)

Happy coding.


One thing to consider, not addressed in the above, is that there may still be multiple in-flight requests (the guard in the 2nd example only shows how to "throw out" old responses, not how to limit requests appropriately). This can be handled with a short-queue and prevention of submitting a new AJAX request until either the reply is obtained or a sufficient "timeout" has expired and the request is considered invalid.

You can try this way also,

 var textInput = document.getElementById('input'); var timeout = null; // default set textInput.onkeyup = function (e) { // If it has already been set cleared first. clearTimeout(timeout); // set timeout to 500ms timeout = setTimeout(function () { console.log('Input Value:', textInput.value); }, 500); }; 
 <input type="text" id="input"> 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM