jQuery.Deferred().тогда, как решить с несколькими параметрами

Поэтому мой API ожидает, что при разрешении конкретного отложенного он получит 2 параметра.

fn().done(function(arg1, arg2) {
  console.log(arg1, arg2);
}).fail(function(err) {
  console.error(err);
});

Теперь, что касается вышеприведенной функции fn, ей нужно сначала дождаться возврата какого-либо другого deferred перед разрешением.

function other() {
  // stubbed out to always resolve
  return $.Deferred().resolve().promise();
}

function fn() {
  return other().then(function() {
    return [1, 2];
  });
}

Но это не работает, потому что arg1 придет как [1, 2], а arg2 будет undefined. Я не могу понять, как вернуть что-то из Deferred.then() первого аргумента функции фильтра успеха, чтобы результирующий отложенный конвейер разрешался с несколькими аргументами.

Конечно, я могу сделать это:

function fn() {
  var done = $.Deferred();
  other().done(function(){
    done.resolve(1, 2);
  }).fail(function(){
    done.reject.apply(done, arguments);
  });
  return done.promise();
}

Но это далеко не так элегантно, как использование .then(), и теперь мне нужно каждый раз беспокоиться об API в случае отрицательного сбоя, хотя я знаю, что просто передаю отклоненное состояние.

И да, я также мог бы изменить fn() API для разрешения массива, но я действительно надеюсь, что для этого есть элегантное решение.


person codefactor    schedule 11.07.2014    source источник
comment
Второй способ не такой короткий, но вызов resolve с двумя параметрами является правильным методом их передачи.   -  person Gone Coding    schedule 11.07.2014
comment
@TrueBlueAussie Итак, я предполагаю, что вы говорите, что ответ заключается в том, что невозможно сделать то, что я хочу, с помощью функции then()?   -  person codefactor    schedule 11.07.2014
comment
Вы могли бы вернуть один анонимный объект с несколькими свойствами, что немного лучше, чем массив? например return {one: 1, two: 2};   -  person Gone Coding    schedule 11.07.2014
comment
@TrueBlueAussie Спасибо за предложение, я думаю, что просто изменю свой API, чтобы ожидать такой объект, потому что я ненавижу обрабатывать состояния готовности/отклонения, я бы предпочел использовать шаблон then()   -  person codefactor    schedule 11.07.2014


Ответы (3)


Вам придется вызывать resolve() или reject() для передачи нескольких аргументов.

.then() не включает никаких механизмов для "распространения" возвращаемой коллекции. Он просто сохранит коллекцию в качестве первого аргумента.

Но он будет взаимодействовать с Deferred или обещанием, которое возвращается. Из абзаца, начинающегося с "Начиная с jQuery 1.8":

Эти функции фильтрации могут возвращать новое значение, которое будет передано в обратные вызовы обещания .done() или .fail(), или они могут возвращать другой наблюдаемый объект (отложенный, обещанный и т. д.), который передаст свое разрешение / отклонение. статус и значения обратных вызовов промисов.

Таким образом, вы можете использовать свой пример other() в качестве основы для fn(), чтобы он был довольно кратким с другим Deferred():

function fn() {
    return other().then(function () {
        return $.Deferred().resolve(1, 2).promise();
    });
}

fn().then(function (a, b) {
    console.log(arguments.length, a, b); // 2 1 2
});

http://jsfiddle.net/cqac2/

person Jonathan Lonowski    schedule 11.07.2014
comment
Это кажется странным, fn().done(function(a){console.log(a)}) затем регистрирует a как объект обещания. - person codefactor; 11.07.2014
comment
@codefactor Deferred() или обещание - это единственное исключение с .then(), которое не будет просто передано. Он привяжет обещание, которое он создает, к предоставленному ему обещанию. Пример из документации: цепочка запросов Ajax. - person Jonathan Lonowski; 11.07.2014
comment
В самом деле?? круто это то что я искал! - person codefactor; 11.07.2014
comment
@Jonathan: я все еще довольно новичок в этом (и, возможно, неправильно понимаю), но не является ли вызов promise() в вашем примере кода избыточным, поскольку обещание видно только методу then(), который (я полагаю) не не пытаетесь решить или отклонить его? - person Mac; 10.08.2015
comment
@Mac Да, наверное, это излишне. Даже если .then() попытается разрешить или отклонить отложенное, оба метода перестанут работать после установки состояния (больше не в ожидании). - person Jonathan Lonowski; 10.08.2015

Обратный вызов, переданный then, может вернуть новый $.Deferred с двумя такими аргументами:

function other() {
  // stubbed out to always resolve
  return $.Deferred().resolve().promise();
}

function fn() {
  return other().then(function() {
    return $.Deferred().resolve(1, 2).promise();
  });
}
person PHP Guru    schedule 14.02.2020

С ES6 вы можете передавать переменное количество аргументов с помощью оператора распространения в $.when() и функции успеха, связанной с .done(//syntax)

$.when(...deferreds).done(
    function (...deferreds) {
        deferreds.forEach(el => {
            console.log("resolved result", el[0].result);
        })
    }).then(function () {
        console.log("do something else");
    });
person dignitas    schedule 17.10.2020