I've been reading about jQuery deferreds and promises and I can't see the difference between using .then()
& .done()
for successful callbacks. I know Eric Hynds mentions that .done()
and .success()
map to the same functionality but I'm guessing so does .then()
as all the callbacks are all invoked on a completion of a successful operation.
Can anyone please enlighten me to the correct usage?
Many thanks
.done()
has only one callback and it is the success callback.then()
has both success and fail callbacks.fail()
has only one fail callbackso it is up to you what you must do... do you care if it succeeds or if it fails?
.done()
terminates the promise chain, making sure nothing else can attach further steps. This means that the jQuery promise implementation can throw any unhandled exception, since no one can possible handle it using.fail()
.In practical terms, if you do not plan to attach more steps to a promise, you should use
.done()
. For more details see why promises need to be doneThere is also difference in way that return results are processed (its called chaining,
done
doesn't chain whilethen
produces call chains)The following results will get logged:
While
will get the following:
---------- Update:
Btw. I forgot to mention, if you return a Promise instead of atomic type value, the outer promise will wait until inner promise resolves:
in this way it becomes very straightforward to compose parallel or sequential asynchronous operations such as:
The above code issues two http requests in parallel thus making the requests complete sooner, while below those http requests are being run sequentially thus reducing server load
There is a very simple mental mapping in response that was a bit hard to find in the other answers:
done
implementstap
as in bluebird Promisesthen
implementsthen
as in ES6 Promisesthen()
always means it will be called in whatever case. But the parameters passing are different in different jQuery versions.Prior to jQuery 1.8,
then()
equalsdone().fail()
. And all of the callback functions share same parameters.But as of jQuery 1.8,
then()
returns a new promise, and if it has return a value, it will be passed into the next callback function.Let's see the following example:
Prior to jQuery 1.8, the answer should be
All
result
takes 3. Andthen()
function always passes the same deferred object to the next function.But as of jQuery 1.8, the result should be:
Because the first
then()
function returns a new promise, and the value 7 (and this is the only parameter that will passed on)is passed to the nextdone()
, so the seconddone()
writeresult = 7
. The secondthen()
takes 7 as the value ofa
and takesundefined
as the value ofb
, so the secondthen()
returns a new promise with the parameter NaN, and the lastdone()
prints NaN as its result.There is actually a pretty critical difference, insofar as jQuery's Deferreds are meant to be an implementations of Promises (and jQuery3.0 actually tries to bring them into spec).
The key difference between done/then is that
.done()
ALWAYS returns the same Promise/wrapped values it started with, regardless of what you do or what you return..then()
always returns a NEW Promise, and you are in charge of controlling what that Promise is based on what the function you passed it returned.Translated from jQuery into native ES2015 Promises,
.done()
is sort of like implementing a "tap" structure around a function in a Promise chain, in that it will, if the chain is in the "resolve" state, pass a value to a function... but the result of that function will NOT affect the chain itself.Those will both log 5, not 6.
Note that I used done and doneWrap to do logging, not .then. That's because console.log functions don't actually return anything. And what happens if you pass .then a function that doesn't return anything?
That will log:
What happened? When I used .then and passed it a function that didn't return anything, it's implicit result was "undefined"... which of course returned a Promise[undefined] to the next then method, which logged undefined. So the original value we started with was basically lost.
.then()
is, at heart, a form of function composition: the result of each step is used as the argument for the function in the next step. That's why .done is best thought of as a "tap"-> it's not actually part of the composition, just something that sneaks a look at the value at a certain step and runs a function at that value, but doesn't actually alter the composition in any way.This is a pretty fundamental difference, and there's a probably a good reason why native Promises don't have a .done method implemented themselves. We don't eve have to get into why there's no .fail method, because that's even more complicated (namely, .fail/.catch are NOT mirrors of .done/.then -> functions in .catch that return bare values do not "stay" rejected like those passed to .then, they resolve!)