jQuery.Deferred().then, how to resolve with multiple parameters

codefactor picture codefactor · Jul 11, 2014 · Viewed 14.6k times · Source

So my API expects that when a particular deferred is resolved it gets 2 params.

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

Now relating to the fn function above, it needs to first wait for some other deferred to return before resolve.

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

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

But this is not working, because arg1 will come as [1, 2] and arg2 will be undefined. I cannot figure out how to return something from Deferred.then() first success filter function argument so that the resulting piped deferred resolves with multiple arguments.

Of course I can do this:

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

But that is not nearly as elegant as using .then() and I now need to worry about the negative failure case API each time even though I know that I'm merely piping the rejected state through.

And yes, I could also change fn() api to resolve with an array, but I am really hoping there is an elegant solution to this.

Answer

Jonathan Lonowski picture Jonathan Lonowski · Jul 11, 2014

You will have to invoke resolve() or reject() in order to pass multiple arguments.

.then() doesn't include any mechanisms for "spreading" a returned collection. It'll just keep the collection intact as the 1st argument.

But, it will interact with a Deferred or promise that's returned. From the paragraph starting with "As of jQuery 1.8":

These filter functions can return a new value to be passed along to the promise's .done() or .fail() callbacks, or they can return another observable object (Deferred, Promise, etc) which will pass its resolved / rejected status and values to the promise's callbacks.

So, you could use your example of other() as the basis for fn() to keep it fairly succinct with another 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/