Reputation: 254886
Keeping in mind this statement:
Once the object has entered the resolved or rejected state, it stays in that state. Callbacks can still be added to the resolved or rejected Deferred — they will execute immediately.
What would you expect this code to produce:
var d = $.Deferred();
var a = function() {
d.done(function() {
console.log('inner');
});
console.log('outer');
};
d.done(a);
d.resolve();
?
I'm expecting it to be inner
, then outer
. Whereas it's not the case for any jquery version I checked.
Would you consider it as a bug or am I missing the point from the description?
Corresponding JSFiddle: http://jsfiddle.net/U8AGc/
UPD: some background for the question: I expect the a
method to behave similarly regardless of how exactly it was invoked: just as an a()
or d.done(a)
Upvotes: 2
Views: 146
Reputation: 664297
I expect the a method to behave similarly regardless of how exactly it was invoked: just as an a() or d.done(a)
No. d.done(a)
does not always call a()
immediately - most prominently when d
is not yet resolved.
Promises/A+ solves this ambiguity by requiring the handlers to be always fired asynchronously, i.e. here you could expect outer
to precede inner
in every case.
I'm expecting it to be
inner
, thenouter
That is prevented by jQuery.Callbacks
, which has an explicit firing
flag for not immediately-executing handlers inside handlers; instead the added handlers are appended to the queue. It's a feature to prevent stack overflows as well, and it simplifies the fire
function by "locking" it.
Would you consider it as a bug or am I missing the point from the description?
I'd consider not following Promises/A+ the bug :-) The description just didn't handle this - quite uncommon - special case.
I'd say its point was that handlers on settled deferreds are still automatically executed even after the resolution, by "immediately" they didn't necessarily mean "synchronously from within .done
" but rather "right away, as soon as possible".
Upvotes: 3
Reputation: 39522
Here's what's happening:
var a = function() {
// the function logging 'inner' is *added* to the call stack
d.done(function() {
console.log('inner');
});
// 'outer' is logged
console.log('outer');
};
// `a` has finished executing, then the anonymous function logs 'inner'
I've added a log with the stack trace* in your JSFiddle - you can see that the function a
is nowhere to be found in the anon function that's logging inner
- jQuery is calling it once a
has finished excecuting.
The relevant line in the jQuery source is found here (notice that it's adding to a queue).
*Trace code from here
Upvotes: 1