Glad you like it.
When I wrote my control flow library, Sexy,
http://github.com/Crabdude/sexy, one of the features I was surprised not to find in other libraries (at least I didn't see any at the time) was error coalescing in the form of one error handler per series (whatever you want to call it). In production, I found myself writing ALOT of redundant dode in the form of:
doSomethingAsync(function(err) {
if (err) return myErrorHandler(err);
try {
// do something
} catch (e) {
myErrorHandler(err);
}
});
Given enough async calls, this can lead to an increase in code bloat on the order of 25% and certainly violates DRY. Control flow libraries make this a little better by wrapping each new callback in a try catch, but I still found myself tediously writing "if (err) return onError(err);" over and OVER again. Having to write 2 lines of code for every 1 line of asynchronous code (100% increase in code bloat per async call) was getting old fast. While I like Sexy, there're some gaps in the API, so I don't use it in production and usually use Step instead for its simplicity, but Step doesn't have Sexy's "sexy" error coalescing. So I sought to add it. Since Tim and I work on the same team and across from each other, I told him about what I was doing that day, and instead he suggested going down the route Tom Robinson had done with long-stack-traces by wrapping node built-ins modules. Tim adapted Tom's long-stack-trace technique to build hook.js and a prototype of the concept, I took the two and finished it up, and trycatch was born. =)
Basically, what long-stack-traces does (though I'd encourage you to read the code) is shim all the built-in module functions that create a new event-source. When you call setTimeout, you're calling a shim which then creates a callback shim and ties the event-source to the hidden callback shim so the long stack trace can be generated. By combining that with the flow-control concept of auto-wrapping with try catch and error coalescing, we're able to now deal with asynchronous uncaught exceptions in a MUCH MORE SANE manner than try-catches EVERYWHERE or process.onUncaughtException. Also, you can't wrap 3rd party code in a try catch, but you can wrap it in a trycatch. =)
In production, the concept of a single request being able to crash the server was mind-boggling to some new to node and generated some not unreasonable push-back. Adding process.onUncaughtException conflated the issue by suppressing some errors we wanted to crash the server, and we found ourselves unable to deal with request-based errors.
At any rate, I'd encourage you to take a look at the internals, as it's a very fun hack to make this work. Basically it uses the V8 JavaScriptStackTraceAPI's Error.prepareStackTrace(error, structuredStackTrace) method to create a custom stack trace and tie callbacks to their event-source. When error.stack is accessed, instead of returning a string, we return an object that returns a long stack trace string and the event-source object so we can traverse up the event-source chain till we find the root trycatch callback.
I'll write a post up on all this when I get the chance, but I definitely think something along these lines belong in core. I've been advocating for a long time the need to be able to detect if a given function is an asynchronous event-source for situations like this, and even more so for better control-flow libraries. Unfortunately, when I asked the panel at NodeConf if they'd ever considered it, I lacked to the proper vocabulary and as a result they didn't quite understand my question and it fell flat. At any rate, THIS (trycatch) does not need to be in node core so much as the ability to detect new event-sources. See the following for reference on the issue:
Manually wrapping built-ins is brittle and guaranteed to miss something if not now, eventually.
Cheers,
Adam Crabtree