【问题标题】:Delay jQuery Ajax in For loop在 For 循环中延迟 jQuery Ajax
【发布时间】:2017-10-03 08:56:10
【问题描述】:

我无法在循环中的 ajax 请求之间进行延迟。 我希望脚本等待 7 秒来执行下一个。请求并不相同,我不知道其中有多少。

$(document).ready(function () {
    var announce = $("#announce").data('id');
    var lots_cnt = parseInt($("#announce").data('lotscnt'));
    for (var i = 0; i < Math.ceil(lots_cnt/20); i++) {
        $.ajax({
                method: "GET",
                url: "/project/lots/"+announce+"/"+(i+1),
                async: false,
                beforeSend: function () {
                    $("#console").append("<strong>Parsing lots from page "+(i+1)+"...</strong><br/>");
                },
                complete:function(){

                },
                success: function (m) {
                    $("#console").append(m);
                    addprogressstep();
                    setTimeout(function() { $("#console").append("Waiting 7 sec ...<br/>"); }, 7000);
                },
                error:function(jqXHR,  textStatus,  errorThrown){

                }
            });
    };

});

【问题讨论】:

  • setTimeout()。也就是说,如果可以避免,发送这么多 AJAX 请求并不是一个好主意。如果可能的话,我建议考虑在一个请求中发送所有数据。但是,您应该绝对删除 async: false,因为这是一种可怕的做法 - 如果您检查控制台,您甚至会看到浏览器告诉您不要使用它。
  • 它看起来并没有那么多请求,它在 1 到 6 之间,所以我认为浏览器和网络对此很好。不幸的是,我不能发出一个请求而不是这个循环,我需要这个延迟来避免“429 Too Many Requests”错误。
  • 浏览器可以使用它,但是如果您有 N 个用户 * N 个请求每分钟发送到服务器,您的服务器/托管公司可能不会。
  • @ГлебГарипов 如果您在实施我的答案时需要帮助,请告诉我
  • @TKoL 感谢您提供帮助,非常感谢。你给了我一个如何解决我的问题的想法。我将在您的答案下方描述我的解决方案。

标签: javascript jquery ajax settimeout delay


【解决方案1】:

这是一个很棒的问题!

我看到您正在使用 jQuery .ajax。根据jQuery documentation$.get() 现在返回一个承诺。我们可以使用 Promise 来实现您想要的。

首先,在你的 for 循环中,for (var i = 0; i &lt; Math.ceil(lots_cnt/20); i++) {,你要做的第一件事就是运行 $.ajax。取而代之的是,我们要做的是构建一个函数数组,其中每个函数都返回一个promise。

var funcArray = [];
// EDIT changed var i to let i
for (let i = 0; i < Math.ceil(lots_cnt/20); i++) {
    var getFunction = function(){
        var getPromise = $.get(...);
        return getPromise;
    }
    funcArray.push(getFunction);
}

然后,您将编写一个递归(ish)函数来处理每个函数,当前一个函数完成时(如果您愿意,可以在超时之后)

function runNext(){
    if (funcArray.length > 0) {
        var nextFunction = funcArray.shift();
        nextFunction() // this is our $.get promise
            .then(function(resultOfGet){
                // do something with your result
                setTimeout(runNext,1000*7);
            })
    }
}

runNext();

--- 编辑 --- 以下是您可以如何将$.ajax 变成承诺的方法:

function ajx(i) {
    return new Promise(function(resolve, reject){
        $.ajax({
            method: "GET",
            url: "/project/lots/"+announce+"/"+(i+1),
            async: false,
            beforeSend: function () {
                $("#console").append("<strong>Parsing lots from page "+(i+1)+"...</strong><br/>");
            },
            complete:function(){

            },
            success: function (m) {
                $("#console").append(m);
                addprogressstep();
                resolve(m);
            },
            error:function(jqXHR,  textStatus,  errorThrown){
                reject(jqXHR,  textStatus,  errorThrown);
            }
        });
    })    
}

【讨论】:

  • 谢谢,我没想到递归。您的代码对我不起作用,它一直试图从 i=6 的 funcArray 执行函数。所以我就这样做了:var lots_cnt = parseInt($("#announce").data('lotscnt')); var pages = Math.ceil(lots_cnt/20); var currentPage=1; function runNext(){ $.get("/goszakup/lots/"+announce+"/"+currentPage,function(m){ $("#console").append(m); addprogressstep(); currentPage++; if(currentPage&lt;=pages) setTimeout(runNext,1000*7); }); } runNext();
  • 啊,是的,当您使用 clojures 以这种方式循环时,变量 'i' 最终总是具有最大值。我没想到。
  • @ГлебГарипов 我认为'i'循环上的错误可以由let而不是var修复。
【解决方案2】:

您可以使用map 而不是for 进行修复。

如果使用地图,您可以更改异步设置true

在处理异步处理时,最好使用map而不是for语句。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-01
    • 2014-01-08
    • 1970-01-01
    • 1970-01-01
    • 2012-09-19
    相关资源
    最近更新 更多