Несколько ajax-вызовов внутри функции each () ... затем что-то сделать, когда ВСЕ из них будут завершены? - PullRequest
8 голосов
/ 04 января 2012

Позвольте мне немного объяснить мой код (извините, если что-то не так, я только что написал этот пример с нуля, он очень близок к тому, что у меня сейчас есть).

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 имеет функцию каждой функции, которая, если имя и связанный адрес электронной почтыиметь значения, он запускает вызов ajax.

Мне нужен способ для выполнения этих вызовов ajax (может быть 1 цикл, может быть 15), а затем, после того как все они завершены, перенаправить на новую страницу.

Нынешний способ, которым я это делаю, ужасен, так как все вызовы ajax не заканчиваются до перенаправления страницы.

Что я могу сделать, чтобы сделать это лучше?Он должен быть защищен от ошибок и ТОЛЬКО перенаправлен после завершения всех вызовов ajax (успех или ошибка, это не имеет значения - просто нужно перенаправить после завершения).

Я пытался использовать async: false но это, кажется, не имеет значения.

Я думал о том, чтобы поместить счетчик в каждую функцию и счетчик в функции успеха ajax, и если они оба совпадают, тогда сделайте перенаправление, ноЯ ищу более опытное руководство.

Ответы [ 4 ]

28 голосов
/ 04 января 2012

Использование отложенных объектов :

$("#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';
    });
});
6 голосов
/ 04 января 2012

Хорошо, это довольно просто, так как вы используете jQuery. jQuery поставляется с интегрированным создателем обещаний, который также связан с вызовами 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() тоже.

2 голосов
/ 04 января 2012

Просто держите счетчик вызовов 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';
                }
            });
        }
    });
});
0 голосов
/ 04 января 2012

По умолчанию $ .ajax является асинхронным. В передаваемый хэш опций добавьте

async: false

Это будет сериализовать звонки, которые вы делаете, если они будут работать так, как вы хотите.


После получения комментария от оригинального постера возможное решение может заключаться в следующем:

  • Внутри отправки вызова определите количество вызовов, которые должны быть сделаны.
  • Сохранить этот результат как локальную переменную в функции-обработчике
  • Создайте обратный вызов для 'complete:', который проверит ценность вызовов
    • Если количество звонков, которые нужно сделать, больше 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;
});
...