Thoughts On: Theseus & Callback Hell

Being able to use functions as first-class objects is a blessing, but common JavaScript patterns result in code that's a mess of callback functions calling each other. To see the problem, consider this code written in a synchronous style:

var img = downloadImage();

Imagine that you load the page and never see the alert message. If you paused the program, the debugger would point you to the exact line of code where execution was waiting for some event to continue—perhaps the download hadn't finished. Alternatively, if an exception had been thrown, there would be a stack trace leading you to the problem site.

Now consider the event-driven version, in which debugging the exact same problem is much harder:

downloadImage(function (img) {
  img.fadeIn(300, function () {

Pausing the debugger won't help: instead of blocking, downloadImage and fadeIn just store the callback pointer in an internal data structure and return immediately.

Stack traces logged for exceptions may not help: an exception that's not thrown within either downloadImage or fadeIn could still interrupt the code path which would have led to the callback functions being invoked.

The only way to determine how much of the code actually executed is to instrument it. In practice, that's done with breakpoints and log statements.