setTimeout not delaying function call in $.each

大兔子大兔子 提交于 2019-12-24 03:26:20

问题


I several divs on my site, I'd like to update one by one. In order not to spam the server with 200+ requests at once, I'd like to delay them by 1s each.

What I tried:

var $tourBox = $('.tour-box');
$tourBox.each(function () {
    var $box = $(this);
    setTimeout(function () {
        getUpdate($box);
    }, 1000);
});

The update function:

function getUpdate($box) {

    var $so = $box.attr('data-so');
    var $url = $('#ajax-route-object-status').val();
    $.get($url, {
        so: $so
    }).success(function (data) {
        var $bg = 'bg-gray';
        if (data.extra.isStarted === true && data.extra.isFinished === false) {
            $bg = 'bg-orange'
        }
        if (data.extra.isStarted === true && data.extra.isFinished === true) {
            $bg = 'bg-green'
        }
        if (data.extra.isLate === true && data.extra.isFinished === false) {
            $bg = 'bg-red'
        }
        $box.removeClass('bg-gray').removeClass('bg-green').removeClass('bg-orange').removeClass('bg-red').addClass($bg);
    });
}

In Chrome Dev--> Network it shows the all loaded as pending and then loads them one by one, but w/out the delay:

As you can see between 3907 and 3940, there is merely half a second delay. This doesn't change even if I have a timeout of 5000.


回答1:


Your for each is calling all of the timeouts at once. It is not waiting one second in between calling each time out. So you have thousands of objects that are being scheduled to call getUpdate($box); after one second.

What you can do is increase the timeout in each iteration.

var $tourBox = $('.tour-box');
var delay = 1000;
$tourBox.each(function () {
    var $box = $(this);
    setTimeout(function () {
        getUpdate($box);
    }, delay);
    delay += 1000;
});

This will cause your first timeout to be fired after 1 second, and your second after two seconds and so on.




回答2:


Back in 2008 I wrote a slowEach() plugin for jQuery that does what you're looking for. It's basically a drop-in replacement for $.each() and $(...).each() that takes a time interval, so the callback is called with that amount of delay for each element:

jQuery.slowEach = function( array, interval, callback ) {
    if( ! array.length ) return;
    var i = 0;
    next();
    function next() {
        if( callback.call( array[i], i, array[i] ) !== false ) {
            if( ++i < array.length ) {
                setTimeout( next, interval );
            }
        }
    }
};

jQuery.fn.slowEach = function( interval, callback ) {
    jQuery.slowEach( this, interval, callback );
};

With that code, you can then do:

$('.tour-box').slowEach( 1000, function() {
    getUpdate( $(this) );
});

One thing to note about this code is that it uses only a single timer at a time, instead of making hundreds of setTimeout() calls to fire up multiple timers at once. This makes it much easier on system resources.




回答3:


Calling one by one could be another solution to avoid spam like request. In that case, this could be a solution:

$(document).ready(function(){

    var $tourBox = $('.tour-box'),
        curIndex = 0,
        totalBox = $tourBox.length,
        url = $('#ajax-route-object-status').val(),


    function getUpdate(){

        var $box = $tourBox.get( curIndex );

        if ( typeof $box === 'undefined'){
            // No more box to process
            return; // exit
        }

        var $so = $box.attr('data-so');

        $.get($url, {
            so: $so
        }).success(function (data) {
            var $bg = 'bg-gray';
            if (data.extra.isStarted === true && data.extra.isFinished === false) {
                $bg = 'bg-orange'
            }
            if (data.extra.isStarted === true && data.extra.isFinished === true) {
                $bg = 'bg-green'
            }
            if (data.extra.isLate === true && data.extra.isFinished === false) {
                $bg = 'bg-red'
            }
            $box.removeClass('bg-gray').removeClass('bg-green').removeClass('bg-orange').removeClass('bg-red').addClass($bg);
        }).always(function(){

            // Increment index to process
            curIndex++;

            // Finished either with success or failed
            // Proceed with next
            getUpdate();
        });       
    }
});


来源:https://stackoverflow.com/questions/45233377/settimeout-not-delaying-function-call-in-each

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!