Reputation: 33
If I create a single Deferred object, then it reports progress like I would expect.
var d1 = function() {
var d = $.Deferred();
d.notify('d1');
d.resolve('d1');
return d.promise();
};
d1().progress(function(a) {
log('Progress: ' + a);
});
However, if I chain two Deferred objects using then(), the progress callbacks are not called.
d1().then(d1).progress(function(a) {
log('Progress: ' + a);
});
It seems to me that then() should propagate the progress notification, but it doesn't appear to be the case. Am I missing something?
I have tested this with jQuery 1.8.0 and 1.8.1. A full working example is here: http://jsfiddle.net/eWQuG/13/
Upvotes: 3
Views: 1007
Reputation: 483
You are doing a few weird things in your tests that are not really logical.
One, you are resolving the promise before you even return it, which defeat the purpose of promises. Promise callbacks are not supposed to be called on previously resolved promises, simple as that.
var p = $.Deferred();
p.then(function(p){log("ok")}).progress(function(p){log("progress " + p)});
p.notify('n1'); // will call handler and be logged
p.resolve();
p.notify('n2'); // will not call handler and will not be logged
Two, you are calling "notify" before you have set the progress callback, but that is somehow still working properly to a degree - it seems jQuery's particular implementation of notify is somewhat async... Except it fails with chaining. How or why, I don't know, but I don't think it is important to debug as your usage is improper anyway.
See this update to your fiddle: http://jsfiddle.net/eWQuG/15/
Upvotes: 1
Reputation: 18078
I can see what's going on but it's slightly tricky to explain. You may have to read this through a couple of times ...
In Test 1, the promise passed to test()
is the "original promise" ie. the object returned by d1()
. Simple.
In Test 2, the object passed to test()
is a new promise resulting from d1().then(d2).then(d3)
. Less simple. This new promise will have inherited only some of the original promise's properties - not including its progressCallbacks (as put in place in the original promise with notify()
). This is reasonable for a promise returned by .then()
, because .then()
is designed to put in place its own doneCallbacks, failCallbacks and progressCallbacks, not to propagate those of the deferred/promise to its immediate left. In short, .then()
does exactly what its name implies - it specifies what is to be done after its preceding deferred/promise has been processed.
You can better see what's going on by keeping a reference to the original promise (ie. the output of d1()
), thus allowing the simple Test 1 to be run both before and after Test 2.
Here is a composite Test 3 :
log('-- Test 3 --');
var p = d1();//p is a promise
test(p);//equivalent to Test 1
test(p.then(d2).then(d3));//equivalent to Test 2
test(p);//equivalent to Test 1 again
In the log, you will see that the behaviour of test(p)
is identical in both cases. However, test(p.then(d2).then(d3))
behaves differently because the object passed is no longer the original promise but a new promise with no progressCallbacks.
Ryan, something maybe worth considering in achieving what you want with :
d1().then(d2).progress(function(a) {
log('Progress: ' + a);
});
is that a the chain can be rearranged as follows :
d1().progress(function(a) {
log('Progress: ' + a);
}).then(d2);
The progress callback is thus applied to the original promise and because .progress()
propagates the original promise down the chain, .then()
will still act as before.
Both versions are valid but would be applicable in different circumstances.
If I'm right then maybe this is the short answer to your question.
Upvotes: 2