7

I'm still trying to wrap my head around using JQuery's Deferred objects, and am scratching my head at one particular problem. In the following code, I initially tried to chain deferred.then() but it never worked. All three functions execute at once. Only after my co-worker pointed me to the pipe function did things fall into place. Question is, why does pipe() work, but not then()?

var otherDefer = function(msg){return function(){return testDefer(msg)}};
var there = otherDefer("there,");
var guy = otherDefer("guy.");                       

function testDefer(msg) {
    var deferred = $.Deferred();
    pretendAjaxCall( function() {
        $('<li>'+msg+'</li>').appendTo('#msgOut');
        deferred.resolve();
    });
    return deferred.promise();  
}

function pretendAjaxCall(callback) {
    setTimeout(callback,1500);
} 

$.when(testDefer("Hi")).pipe(there).then(guy);​

I also tried return deferred instead of return deferred.promise() when using when().then().then().

jsFiddle for above code: http://jsfiddle.net/eterpstra/yGu2d/

eterps
  • 14,198
  • 4
  • 35
  • 46
  • The fiddle works fine for me using "then().then()" (Chrome). – Marcelo De Zen Sep 04 '12 at 23:35
  • the way I understand it, `.then` returns the original deferred object, allowing for other then, done, fail, etc calls on it. `.pipe` filters the result and can return a new deferred/promise and any subsequent thens, dones, fails in the chain will act on that object rather than the original. – MrOBrian Sep 04 '12 at 23:57
  • this above answer is for Jquery 1.8 and below, read below answers – Sundara Prabu May 25 '17 at 19:31

3 Answers3

6

Since jQuery 1.8 then() returns a new Promise (the same as pipe()) instead of the same Deferred that when() returns.

Change the jQuery version to 1.8.3 or above in your example at:

http://jsfiddle.net/eterpstra/yGu2d

and

$.when(testDefer("Hi")).then(there).then(guy);

will work.

  • At the time this question was asked, [jQuery 1.8 was still quite new](http://blog.jquery.com/2012/08/09/jquery-1-8-released/) which is probably why none of the older answers suggest updating. Still, good to have an update for future users facing this problem so they don't start using deprecated functions in new code. – Mattias Buelens Jul 13 '13 at 15:17
5

This is how then() and pipe() work in your sample:

then() returns Deferred and by calling then() on this same Deferred you simply add a second callback to it which will be called simultaneously with the first one

pipe(), instead, returns new Promise allowing you to build a chain and that's why you get sequential calls in this case


Take a look at the following resources for more info about pipe/then:

When should I use jQuery deferred's "then" method and when should I use the "pipe" method?

Promise Pipelines in JavaScript

Community
  • 1
  • 1
maxnk
  • 5,755
  • 2
  • 27
  • 20
2

You're using .then in a way it's not supposed to be used--you're arguing a Deferred to it, when all that .then expects is a plain function to be added as a callback.

The .then method returns the original Deferred, which has been resolved already. When the Deferred resolves, all callbacks added with .then are executed immediately.

On the other hand, the .pipe function takes either a set of functions, or a Promise (which is what you're sending it) and resolves based on the status of the original Deferred. The functionality of .pipe is actually what you're looking for!

zetlen
  • 3,609
  • 25
  • 22