each() 函数中的多个 ajax 调用.. 然后在所有这些都完成后执行一些操作?

Posted

技术标签:

【中文标题】each() 函数中的多个 ajax 调用.. 然后在所有这些都完成后执行一些操作?【英文标题】:Multiple ajax calls inside a each() function.. then do something once ALL of them are finished? 【发布时间】:2012-02-02 07:20:42 【问题描述】:

让我稍微解释一下我的代码(如果有问题请见谅,我刚刚从头开始编写这个示例,它与我目前的非常接近)。

HTML:

<form id="form">
    <!-- Friend 1 -->
    Name 1: <input type="text" name="friendName1" id="friendName1" class="friendName" value=""><br />
    Email 1: <input type="text" name="friendEmail1" id="friendEmail1" value=""><br /><br />
    <!-- Friend 2 -->
    Name 2:<input type="text" name="friendName2" id="friendName2" class="friendName" value=""><br />
    Email 2:<input type="text" name="friendEmail2" id="friendEmail2" value=""><br /><br />
    <!-- Friend 3 -->
    Name 3:<input type="text" name="friendName3" id="friendName3" class="friendName" value=""><br />
    Email 3:<input type="text" name="friendEmail3" id="friendEmail3" value=""><br /><br />
    <!-- Friend 4 -->
    Name 4:<input type="text" name="friendName4" id="friendName4" class="friendName" value=""><br />
    Email 4:<input type="text" name="friendEmail4" id="friendEmail4" value=""><br /><br />
    <!-- Submit -->
    <input name="submit" type="submit" value="Submit">
</form>

JS:

$("#form").submit(function()

    $(".friendName[value!='']").each(function()
        var idEmail = 'friendEmail' + $(this).attr("id").replace('friendName','');
        if($("#"+idEmail+"[value!='']").length > 0)
            var name = $(this).val();
            var email = $("#"+idEmail).val();

            // Submit the ajax request
            $.ajax( 
                type: 'POST', 
                url: 'ajax/url', 
                data: 
                    name: name,
                    email: email
                ,
                success: function(json) 
                    // Log a console entry if our ajax request was successful
                    console.log(name + " was submitted via ajax");
                
            );
        
    );

    // Redirect the user to the thank you page
    setTimeout( function()  window.location= '/thanks'; , 2000 );

);

JSFiddle(重定向已移除,ajax 调用替换为小提琴的控制台日志)

http://jsfiddle.net/cM5PX/

html 是一个简单的表单,带有朋友姓名和朋友电子邮件输入字段。

JS 有一个 each 函数,如果 name 和关联的 email 有值,它会运行一个 ajax 调用。

我需要一种方法让这些 ajax 调用运行(可能有 1 个循环,可能有 15 个),然后在它们全部完成后,重定向到新页面。

我目前的做法很糟糕,因为所有的 ajax 调用都没有在页面重定向之前完成运行。

我可以做些什么来改善它?它需要是万无一失的,并且只有在所有 ajax 调用完成后才重定向(成功或错误,没关系 - 它只需要在完成后重定向)。

我尝试过使用async: false,但似乎没有什么不同。

我曾考虑在每个函数中放置一个计数器,在 ajax 成功函数中放置一个计数器,如果它们都匹配,则进行重定向,但我正在寻找一些更有经验的指导。

【问题讨论】:

【参考方案1】:

使用deferred objects:

$("#form").submit(function(e)

    e.preventDefault();

    var calls = [];

    $(".friendName[value!='']").each(function()
        // Submit the ajax request
        calls.push($.ajax( 
            type: 'POST', 
            url: 'ajax/url', 
            data: 
                name: name,
                email: email
             ,
             success: function(json) 
                // Log a console entry if our ajax request was successful
                console.log(name + " was submitted via ajax");
             
         ));
    );

    $.when.apply($, calls).then(function() 
        window.location= '/thanks';
    );
);

【讨论】:

这听起来很聪明,我会试一试,让你知道我是怎么做的。 这太棒了,难怪你有157k! ;) 很好的答案!【参考方案2】:

好的,这很容易,因为您使用的是 jQuery。 jQuery 带有一个集成的 Promise maker,它也与 jQuery 的 Ajax 调用相连。那是什么意思?好吧,我们可以这样轻松地进行:

var requests = [ ];

// ...

// Submit the ajax request
requests.push($.ajax( 
    type: 'POST', 
    url: 'ajax/url', 
    data: 
        name: name,
        email: email
    ,
    success: function(json) 
        // Log a console entry if our ajax request was successful
        console.log(name + " was submitted via ajax");
    
));

// at this point we filled our array with jXHR objects which also inherit the promise API

$.when.apply( null, requests ).done(function() 
    document.location.href = '/thanks';
);

注意:上面的代码只有在所有请求都成功完成的情况下才会触发。如果您需要处理一个或多个请求失败的情况,也可以使用.then().fail() 而不是.done()

【讨论】:

Felix 打败了你! :( +1 虽然。 确实,我做的“blabla”太多了:p 确实,这里没有第二名:p【参考方案3】:

只需保留 AJAX 调用的计数器并检查它们何时全部完成。 像这样的:

$("#form").submit(function()
    var ajaxMax = $(".friendName[value!='']").length, ajaxCounter = 0;
    $(".friendName[value!='']").each(function()
        var idEmail = 'friendEmail' + $(this).attr("id").replace('friendName','');
        if($("#"+idEmail+"[value!='']").length > 0)
            var name = $(this).val();
            var email = $("#"+idEmail).val();

            // Submit the ajax request
            $.ajax( 
                type: 'POST', 
                url: 'ajax/url', 
                data: 
                    name: name,
                    email: email
                ,
                success: function(json) 
                    // Log a console entry if our ajax request was successful
                    console.log(name + " was submitted via ajax");
                    if(++ajaxCounter >= ajaxMax)
                        window.location= '/thanks';
                
            );
        
    );
);

【讨论】:

我刚刚意识到我发布的代码不能完全正常工作,因为你有一个“if”语句,所以在计算“max”时需要检查它。【参考方案4】:

默认情况下 $.ajax 是异步的。在传递的选项哈希中,添加

async: false

这将序列化你正在进行的调用,让它按照你想要的方式执行。


在得到原发帖人的评论后,可能的解决办法是:

在提交调用中确定应该进行的调用次数。 将此结果存储为处理函数中的局部变量 在“完成:”上创建一个回调,它将检查调用的值 如果要调用的次数大于0,则递减该值并返回 如果调用次数为零,请更新 window.location(确实应该使用 window.location.href,因为 window.location 是一个对象,但浏览器会允许这样做并正确执行)

注意,我没有关于执行这种操作的线程安全的任何信息,所以 YMMV。


示例代码:

$("#form").submit(function(eventObject)
    var $ajaxFields= $(".friendName[value!='']").filter(function(index)
        var idEmail = 'friendEmail' + $(this).attr("id").replace('friendName','');
        return ($("#"+idEmail+"[value!='']").length > 0);
    );

    var numberToSubmit= $ajaxFields.length;
    $ajaxFields.each(function()
        var idEmail = 'friendEmail' + $(this).attr("id").replace('friendName','');
        var name = $(this).val();
        var email = $("#"+idEmail).val();

        // Submit the ajax request
        $.ajax( 
            type: 'POST', 
            url: 'ajax/url', 
            data: 
                name: name,
                email: email
            ,
            success: function(json) 
                // Log a console entry if our ajax request was successful
                console.log(name + " was submitted via ajax");
            ,
            error: function(jqXHR, textStatus, errorThrown) 
                console.log("call not completed: "+textStatus);
            ,
            complete: function(jqXHR, textStatus) 
                if( --numberToSubmit == 0 ) 
                    window.location.href= '/thanks';
                
            
        );
    );

    // Prevent default form submission
    return false;
);

【讨论】:

刚刚更新了我的问题,我尝试使用 async: false 但它似乎没有什么不同,我真的不希望浏览器在通话时冻结。 啊好吧...让我挖掘一下。 下面的评论使用延迟对象可能是更聪明的方法,不幸的是我没有任何使用它们的经验。

以上是关于each() 函数中的多个 ajax 调用.. 然后在所有这些都完成后执行一些操作?的主要内容,如果未能解决你的问题,请参考以下文章

使用ajax jQuery for-each函数在表中追加多个数据

jquery中的多个ajax调用

无法在 ajax 调用中访问 Url.Action 中的项目

第117天:Ajax实现省市区三级联动

如何通过主干中的 ajax 调用使用模型渲染多个视图

jQuery 最喜欢的函数调用 api 与 ajax