[jquery] jQuery deferreds and promises - .then() vs .done()

Only use .then()

These are the disadvantages of .done()

  • can not be chained
  • block resolve() call (all .done() handlers will be executed synchronous)
  • resolve() might get an exception from registered .done() handlers(!)
  • an exception in a .done() half-kills the deferred:
    • further .done() handlers will be silently skipped

I thought temporarily that .then(oneArgOnly) always requires .catch() so that no exception gets silently ignored, but that is not true any more: the unhandledrejection event logs unhandled .then() exceptions on the console (as default). Very reasonable! No reason left to use .done() at all.

Proof

The following code snippet reveals, that:

  • all .done() handlers will be called synchronous at point of resolve()
    • logged as 1, 3, 5, 7
    • logged before the script falls through bottom
  • exception in a .done() influences resolve() caller
    • logged via catch around resolve()
  • exception breaks promise from further .done() resolution
    • 8 and 10 are not logged!
  • .then() has none of these problems
    • logged as 2, 4, 6, 9, 11 after thread turns idle
    • (snippet environment has no unhandledrejection is seems)

Btw, exceptions from .done() can’t be properly caught: because of the synchronous pattern of .done(), the error is either thrown at the point of .resolve() (might be library code!) or at the .done() call which attaches the culprit if the deferred is already resolved.

_x000D_
_x000D_
console.log('Start of script.');_x000D_
let deferred = $.Deferred();_x000D_
// deferred.resolve('Redemption.');_x000D_
deferred.fail(() => console.log('fail()'));_x000D_
deferred.catch(()=> console.log('catch()'));_x000D_
deferred.done(() => console.log('1-done()'));_x000D_
deferred.then(() => console.log('2-then()'));_x000D_
deferred.done(() => console.log('3-done()'));_x000D_
deferred.then(() =>{console.log('4-then()-throw');_x000D_
    throw 'thrown from 4-then()';});_x000D_
deferred.done(() => console.log('5-done()'));_x000D_
deferred.then(() => console.log('6-then()'));_x000D_
deferred.done(() =>{console.log('7-done()-throw');_x000D_
    throw 'thrown from 7-done()';});_x000D_
deferred.done(() => console.log('8-done()'));_x000D_
deferred.then(() => console.log('9-then()'));_x000D_
_x000D_
console.log('Resolving.');_x000D_
try {_x000D_
    deferred.resolve('Solution.');_x000D_
} catch(e) {_x000D_
    console.log(`Caught exception from handler_x000D_
        in resolve():`, e);_x000D_
}_x000D_
deferred.done(() => console.log('10-done()'));_x000D_
deferred.then(() => console.log('11-then()'));_x000D_
console.log('End of script.');
_x000D_
<script_x000D_
src="https://code.jquery.com/jquery-3.4.1.min.js"_x000D_
integrity="sha384-vk5WoKIaW/vJyUAd9n/wmopsmNhiy+L2Z+SBxGYnUkunIxVxAv/UtMOhba/xskxh"_x000D_
crossorigin="anonymous"_x000D_
></script>
_x000D_
_x000D_
_x000D_