doSomething(function (err) {
doSomethingElse(function (err) {
doYetAnotherThing(function (err) {
throw new Error(
"I don't bubble up to the top of the stack, " +
"because there is no stack!");
});
});
});
BTW a great trick is to tick the little "Async" box in the Chrome Dev Tools, so you can get a full stacktrace showing exactly where you came from. It works for both callbacks and promises: http://www.html5rocks.com/en/tutorials/developertools/async-...Naive event-based code is somewhat like a goto, in that every time an event comes in, you get a new stack constructed for that event. While you then get a stack if you call functions from the initial handler, every event that comes in whacks the stack afresh. So it isn't "the same as" a goto, but it does hurt the stack. Instead of a stack frame that represents the whole of the program, you get a series of "island" stack frames.
In some sense, this is the most fundamental reason why event-based programming is so painful, and it's the problem that all these multitudinous programming "async" techniques are trying to get around. Promises, for instance, can be looked at as a partial way of having a sort of stack around a particular sequence of operations that may be interrupted in arbitrary locations by this event-induced stack discarding. In this sense they can also be viewed as an inner-platform problem; where the language has "try/catch", for loops, etc, promises end up trying to recreate all that in a second layer above the bottom layer, with all the corresponding complexity of embedding a language in the language.
If you then end up asking, "Well, what if we just didn't discard the stack in the first place?", you end up in Erlang/Go/Haskell/Scala land.