【问题标题】:jQuery Ajax Wait Each FunctionjQuery Ajax 等待每个函数
【发布时间】:2015-07-17 18:20:11
【问题描述】:
$xy('#simpan').click(function() {

  $xy('input[id="cekbok[]"]:checked').each(function() {

    var data = (this.value);
    var div = (this.value);
    var str = window.location.href;
    var res = str.replace("wp-admin/options-general.php?page=katalogu-options", "/wp-content/plugins/katalog/includes/img/loading.gif");
    var loading = ('<img src="'+res+'">') ;


    $xy.ajax({
        type : 'POST',
        url : '../wp-content/plugins/katalogunique/proses2.php',           
        data: {
            id  : (this.value)
        },

        success:function (data) {
            $xy('#result'+div).empty();
            $xy('#result'+div).append(data);
            $xy('#tz'+div).remove();
        }          

    });  

  });
});

我的函数在循环中将复选框值发送到proses2.php,但是当我运行此脚本时,它将一次运行所有 ajax POST 调用。我想逐个运行 ajax 请求或等到完成,我该如何解决这个问题?

【问题讨论】:

  • 它将运行所有 ajax POST 是什么意思?请解释一下。而且,查看$xy('input[id="cekbok[]"]:checked'),您似乎有不止一个checkbox 具有相同的ID,这是错误的,因为ID 在任何给定文档中必须是唯一的!也发布您的HTML
  • 如果我选中 10 个复选框,那么它将运行 10 个 Ajax 帖子到 proses2.php,是的,复选框 ID 是唯一的,这个脚本已经可以工作,但我想让它一个一个地执行...谢谢跨度>
  • 理想情况下你想达到什么目的

标签: javascript jquery ajax promise jquery-deferred


【解决方案1】:

这是一种没有递归并使用简单循环的方法:

$xy('#simpan').click(function() {

    var url = '../wp-content/plugins/katalogunique/proses2.php';
    var d = $.Deferred().resolve(); // empty promise
    $xy('input[id="cekbok[]"]:checked').each(function() {
        var div = this.value;
        d = d.then(function(data){
            $xy('#result'+div).empty().append(data);
            $xy('#tz'+div).remove();
            return $xy.post(url, {id: div}); // this will make the next request wait
        });
    });
    // can d.then here for knowing when all of the requests are done.
});

请注意,我可以通过 .reduce 将行数从 6 缩短到 4 来“巧妙地解决这个问题”,但老实说,我宁愿让循环结构 OP 保持舒适。这是因为 Promise 链接而起作用 - 基本上,当您从 then 返回一个操作时,它会在执行下一个链接到的 then 之前等待它。

让我们举例说明:

function log(msg){ // simple function to log stuff
    document.body.innerHTML += msg + "<br />";
}

var delay = function(ms){ // this is an async request, simulating your AJAX
   var d = $.Deferred();
   setTimeout(d.resolve, ms); // resolving a deferred makes its then handlers execute
   return d;
};

// $.Deferred.resolve() starts a new chain so handlers execute
var p = $.Deferred().resolve().then(function(){ 
    log("1");
    return delay(1000); // like in your code, we're waiting for it when we chain
}).then(function(){ // in the above code, this is the d = d.then part,
    log("2"); // this only runs when the above delay completes
    return delay(1000);
});

// and more like in the above example, we can chain it with a loop:
[3,4,5,6,7,8,9,10].forEach(function(i){
     p = p.then(function(){
         log(i);
         return delay(1000);
     });
});
&lt;script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"&gt;&lt;/script&gt;

请注意,$xy('#result'+div) 可能是个坏主意,因为您正在查询视图层以查找放置在那里的内容 - 考虑将相关 div 保留为数组并保留引用:)

【讨论】:

  • 承诺的忠实粉丝,非常酷。最好更详细地解释这一点,因为它会混淆除了被推迟的顽固分子之外的所有人:)
  • 我同意这是最干净的解决方案
  • @TrueBlueAussie 谢谢,我已经添加了一些解释它的词。我将添加一个简单的示例。
  • @TrueBlueAussie 我已经添加了一个示例,让我知道这是否更好。
  • @SintaCumeliani 很高兴我能帮上忙,值得一提的是,jQuery 中的很多东西都返回了 Promise,因此您也可以通过这种方式等待动画(通过返回 $("来自thenthening 它的animatedElement").promise()。快乐编码。 (Example of chaining animations)
【解决方案2】:

您可以使用这样的递归函数一个接一个地执行所有调用:

$xy('#simpan').click(function() {
    var str = window.location.href;
    var i=0; things = $xy('input[id="cekbok[]"]:checked');
    (function doOneTask(){
        if (i++>=things.length) return;
        var thing = things[i];
        var data = thing.value;
        var div = thing.value;
        var res = str.replace("wp-admin/options-general.php?page=katalogu-options", "/wp-content/plugins/katalog/includes/img/loading.gif");
        var loading = ('<img src="'+res+'">') ;
        $xy.ajax({
            type : 'POST',
            url : '../wp-content/plugins/katalogunique/proses2.php',           
            data: {
                id  : thing.value
            },
            success:function (data) {
                $xy('#result'+div).empty();
                $xy('#result'+div).append(data);
                $xy('#tz'+div).remove();
            }          
        }).always(doOneTask);
    })();
});

注意:如果您想在第一次失败时停止,而不是像我一样进行下一次调用,请将 always 替换为 done

【讨论】:

  • 不是var data = thing.value;吗?显然这是重复的。
  • @LShetty 是的,忘记了这个变化
  • 早点开始做得很好,但是在递归函数之外初始化变量,以便在其中使用,闻起来很不对劲。当然传递一个简化的列表可以让它完全独立,没有外部依赖或初始化? PS。您仍然在函数内部到处引用this,这是不正确的。
  • @TrueBlueAussie 在一个地方使用它时,我更喜欢使用闭包而不是传递参数。但没有太大区别。
  • 很公平:你又错过了一个this
【解决方案3】:

一种方法是使用递归函数,每次都将列表(减去第一个条目)传递回去。

例如调用代码简化为:

$xy('#simpan').click(function() {
    LoadAjax($xy('input[id="cekbok[]"]:checked'));

});

LoadAjax 是这样递归的:

function LoadAjax(elements) {
    // Exit when done
    if (!elements.length) return;
    var $this = elements.first();
    var data = ($this.value);
    var div = ($this.value);
    var str = window.location.href;
    var res = str.replace("wp-admin/options-general.php?page=katalogu-options", "/wp-content/plugins/katalog/includes/img/loading.gif");
    var loading = ('<img src="' + res + '">');

    $xy.ajax({
        type: 'POST',
        url: '../wp-content/plugins/katalogunique/proses2.php',
        data: {
            id: ($this.value)
        },

        success: function (data) {
            $xy('#result' + div).empty();
            $xy('#result' + div).append(data);
            $xy('#tz' + div).remove();
            // Go recursive with the rest of the list
            LoadAjax(elements.slice(1));
        }

    });
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-10-19
    • 2019-04-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-22
    • 2012-07-19
    相关资源
    最近更新 更多