Как работать с группой deferred’ов, когда один из них терпит неудачу

У меня есть серия вызовов ajax, которые заполняют столбцы на странице.

var doneDefers = function(defer) {
        // leftColDefer is another deferred that sets some header info
    $.when(defer, leftColDefer).done(function(req1, req2){
        var data = req1[0],
        head = req2[0];
        // spit this data out to elements on the page   

    });
};  
for(i=0;i<window.ids.length;i++){
    defer[i] =  $.ajax({
        url: 'api/get_runs_stats.php',
        type: 'GET',
        dataType: 'json',
        data: {
            run_id: window.ids[i]
        }
    });
    doneDefers(defer[i]);
}

Это прекрасно работает. Если вызов ajax терпит неудачу, ничего не выплевывается, и с миром все в порядке. Теперь я хочу сделать некоторые расчеты на основе всех данных, которые выплевываются.

$.when.apply(null, defer)
    .done(function() {
        var args = Array.prototype.slice.call(arguments);
        calcDeltas();

    })
    .fail(function() {
        var args = Array.prototype.slice.call(arguments);
        console.log('in list fail');
    });

Готовая функция работает нормально, ни один из вызовов ajax не терпит неудачу. Если один из них терпит неудачу, я перехожу к функции сбоя, и у меня нет доступа ни к каким возвращаемым данным из других прогонов. Массив аргументов содержит только данные неудачного вызова.

Я хотел бы сделать свои расчеты на переданных наборах данных. Как я могу получить данные от хороших вызовов, когда один из них не работает?


person Barbara Laird    schedule 23.01.2014    source источник
comment
Вы говорите, что если какой-либо из ваших вызовов ajax в массиве отсрочки отказа цикла for будет пустым?   -  person Mina Gabriel    schedule 23.01.2014
comment
Барбара, помните, что когда какой-либо из аргументов промиса терпит неудачу, $.when() немедленно запускает обработчик (обработчики) сбоя, не дожидаясь, пока другие аргументы промиса будут разрешены или завершатся ошибкой. $.when() не пытается сделать доступным для своего обработчика (ов) сбоев то, что не гарантируется, что это то, о чем вы, кажется, просите.   -  person Beetroot-Beetroot    schedule 23.01.2014
comment
@Beetroot-Beetroot Можно ли в этом случае получить обработчик с разрешенными результатами? Или мне нужно вернуться к какой-то глобальной схеме счетчика?   -  person Barbara Laird    schedule 23.01.2014
comment
@MinaGabriel Вызывается обработчик сбоев, и его параметры соответствуют тому, что я ожидал бы для 1 неудачного вызова ajax. Он не включает разрешенные параметры. Имеет ли это смысл? Если нет, я могу добавить примеры результатов к вопросу.   -  person Barbara Laird    schedule 23.01.2014
comment
ну, единственный раз, когда я помню, что у меня был цикл for и вызов ajax, я делал это pastebin.com/ikeMwJQq и у меня не было никаких проблем, надеюсь, это поможет вам   -  person Mina Gabriel    schedule 23.01.2014
comment
Спасибо @MinaGabriel. Если я правильно понимаю, это обработчик каждого вызова ajax. Эта часть работает на меня. Мне нужно позаботиться об обработчике завершения всех вызовов ajax. Мне нужно выполнить некоторую обработку, когда все вызовы завершатся, даже если некоторые из них потерпят неудачу.   -  person Barbara Laird    schedule 23.01.2014


Ответы (1)


Я не уверен, что это самое простое решение, но у него есть шанс сработать.

var ajax_always_promises = [],//to be populated with promises that (barring uncaught error) are guaranteed to be resolved.
    data_arr = [],//an array to be (sparsely) populated with asynchronously delivered json data.
    error_arr = [];//an array to be (sparsely) populated with ajax error messages.

$.each(window.ids, function(i, id) {
    var dfrd = $.Deferred();
    var p = $.ajax({
        url: 'api/get_runs_stats.php',
        type: 'GET',
        dataType: 'json',
        data: {
            run_id: window.ids[i]
        }
    }).done(function(json_data) {
        data_arr[i] = json_data;//intentionally not `data_arr.push(json_data);`
    }).fail(function(jqXHR, textStatus, errorThrown) {
        error_arr[i] = textStatus;//intentionally not `error_arr.push(textStatus);`
    }).always(dfrd.resolve);

    ajax_always_promises[i] = dfrd.promise();
    doneDefers(p);
});

$.when.apply(null, ajax_always_promises).done(function() {
    //The data in the (sparsely) populated arrays `data_arr` and `error_arr` is available to be used. 
    var i, id, success_count=0, error_count=0;
    for(i=0; i<Math.max(data_arr.length,error_arr.length); i++) {

        //Here, the index i corresponds to the original index of window.ids ...
        //...that's the advantage of sparsely populating the arrays.
        id = window.ids[i];
        if(data_arr[i]) {
            //Here, do whatever is required with `data_arr[i]`, and `id` if needed.
            success_count++;
        }
        else if(error_arr[i]) {
            //Here, do whatever is required with `error_arr[i]`, and `id` if needed.
            error_count++;
        }
    }
    console.log("Success:errors: " + success_count + ':' + error_count);
});

Не тестировалось — возможно, потребуется отладка

person Beetroot-Beetroot    schedule 24.01.2014