Аргументы обратного вызова jQuery Deferred's, $ .when () и fail () - PullRequest
22 голосов
/ 01 апреля 2011

Я получаю неожиданный результат при использовании $.when(), когда одна из отложенных операций не выполняется.

Возьми этот JavaScript, который создал 2 отсрочки. Первый успешен, а второй - нет.

var f1 = function() {
    return $.Deferred(function(dfd) {
        dfd.resolve('123 from f1');
    }).promise();
};

var f2 = function() {
    return $.Deferred(function(dfd) {
        dfd.reject('456 from f2');
    }).promise();
};

$.when(f1(), f2())
    .then(function(f1Val, f2Val) {
        alert('success! f1, f2: ' + JSON.stringify([f1Val, f2Val]));
    })
    .fail(function(f1Val, f2Val) {
        alert('fail!    f1, f2: ' + JSON.stringify([f1Val, f2Val]));
    });

Запустите его сами: http://jsfiddle.net/r2d3j/2/

Я получаю fail! f1, f2: ["456 from f2", null]

Проблема в том, что в обратном вызове .fail() значение, переданное с отклонением f2(), направляется на первый аргумент, где я ожидаю f1Value. Это означает, что у меня нет способа узнать, к какому отложенному объекту действительно добавлен этот reject(), и я также не знаю, к какой операции принадлежат данные об ошибках.

Я бы ожидал, что .fail() получит аргументы null, '456 from f2', так как первая отложенная не потерпела неудачу. Или я просто не правильно делаю отсрочку здесь?

Как я могу узнать, какие отложенные сбои и какие аргументы отклонения принадлежат тому, с каким сбоем отложенного, если порядок аргументов в обратном вызове не соблюден?

Ответы [ 4 ]

25 голосов
/ 25 октября 2011

$.when() немедленно выполнит неудачный обратный вызов (2-й параметр, переданный в then()), если какой-либо из параметров потерпит неудачу.Это по замыслу.Чтобы процитировать документацию:

http://api.jquery.com/jQuery.when/

В случае множественных отсрочек, когда один из отложенных отклонен, jQuery.when немедленно запускает failCallbacks для своего главного отложенного элемента.Обратите внимание, что некоторые из отложенных могут все еще быть неразрешенными в этой точке.Если вам необходимо выполнить дополнительную обработку для этого случая, например отменить незаконченные запросы Ajax, вы можете хранить ссылки на базовые объекты jqXHR в замыкании и проверять / отменять их в failCallback.

Естьна самом деле нет встроенного способа получения обратного вызова, который ожидает, пока все они не будут завершены, независимо от их статуса успеха / неудачи.

Итак, я построил $.whenAll() для вас :)
Он всегда ждетпока все они не решатся, так или иначе:

http://jsfiddle.net/InfinitiesLoop/yQsYK/51/

$.whenAll(a, b, c)
    .then( callbackUponAllResolvedOrRejected );
5 голосов
/ 02 апреля 2011

Внутренне пути «отклонить» и «потерпеть неудачу» обрабатываются двумя совершенно разными очередями, поэтому он просто не работает так, как вы ожидаете.Группа «when ()» может позволить им передавать себя вместе с вызовом «.reject ()» как часть литерала объекта или чего-то еще.

0 голосов
/ 21 мая 2012

http://jsfiddle.net/InfinitiesLoop/yQsYK/

Это всегда будет отклоняться, если задано несколько входов. rejected = true; должно быть rejected |= reject;

0 голосов
/ 17 февраля 2012

Я столкнулся с той же проблемой, и я справился с ней, используя обратный вызов .always и осмотрев мой массив отложенных объектов. У меня было неизвестное количество вызовов ajax, поэтому мне пришлось сделать следующее:

// array of ajax deletes
var deletes = [];
$checkboxes.each(function () {
    deletes.push(deleteFile(this));
});

$.when.apply($, deletes)
  .always(function () {
      // unfortunately .fail shortcircuits and returns the first fail,
      // so we have to loop the deferred objects and see what happened.

      $.each(deletes, function () {
          this.done(function () {
              console.log("done");
          }).fail(function () {
              console.log("fail");
          });
      });
  });

Метод deleteFile возвращает обещание с обратными вызовами .done или .fail.

Это позволяет вам действовать после того, как все отсрочки завершены. В моем случае я собираюсь показать сводку об ошибке удаления файла.

Я только что попробовал это сделать, и, к сожалению, мне пришлось установить интервальный таймер, чтобы убедиться, что все они действительно выполнены после того, как я $ .each на отложенных объектах. Это кажется странным и нелогичным.

Все еще пытаюсь понять эти отсрочки!

...