【问题标题】:setTimeout not delaying function call in $.eachsetTimeout 不延迟 $.each 中的函数调用
【发布时间】:2017-07-21 08:57:50
【问题描述】:

我的网站上有几个 div,我想一一更新。为了不一次向服务器发送超过 200 个请求的垃圾邮件,我希望每个请求延迟 1 秒。

我尝试了什么:

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

更新函数:

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);
    });
}

在 Chrome Dev--> Network 中,它显示所有已加载为待处理,然后一一加载,但没有延迟:

如您所见,在 3907 和 3940 之间,只有半秒的延迟。即使我的超时时间为 5000,这也不会改变。

【问题讨论】:

  • 你是什么意思'每个 1s。'?您的意思是每个请求都会以一秒的间隔发出,还是所有请求都将在 1 秒后发出?因为这就是你的代码正在做的事情。 setTimeout 不会暂停 javascript 的执行。您的代码正在做的是在一秒钟后设置所有获取请求
  • 它按预期工作的回调应该是这样工作的。请查看prashantb.me/javascript-call-stack-event-loop-and-callbacks 以更好地了解回调函数的工作原理。

标签: javascript jquery ajax get settimeout


【解决方案1】:

早在 2008 年,我写了 a slowEach() plugin for jQuery,它可以满足您的需求。它基本上是 $.each()$(...).each() 的替代品,需要一个时间间隔,因此调用回调时每个元素都有相应的延迟:

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 );
};

使用该代码,您可以执行以下操作:

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

关于此代码需要注意的一点是,它一次只使用一个计时器,而不是一次调用数百个setTimeout() 来启动多个计时器。这样可以更轻松地占用系统资源。

【讨论】:

    【解决方案2】:

    您的 for each 一次调用所有超时。它不会在每次调用之间等待一秒钟。因此,您有数千个对象计划在一秒钟后调用getUpdate($box);

    你可以做的是增加每次迭代的超时时间。

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

    这将导致您的第一次超时在 1 秒后触发,第二次超时在 2 秒后触发,以此类推。

    【讨论】:

    • 这适用于较小的数组,但您应该小心进行可能大量的setTimeout() 调用。任何时候只要有一个setTimeout() 处于活动状态,就很容易做到这一点。不要以增加延迟的方式启动大量 setTimeout() 呼叫,只需对每个呼叫使用相同的延迟,但在处理前一个呼叫后启动新的 setTimeout()
    【解决方案3】:

    逐个调用可能是另一种避免垃圾邮件之类的请求的解决方案。 在这种情况下,这可能是一个解决方案:

    $(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();
            });       
        }
    });
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-08-22
      • 1970-01-01
      • 2015-02-22
      • 1970-01-01
      • 2018-09-17
      • 2021-02-23
      • 1970-01-01
      相关资源
      最近更新 更多