Hacker News new | ask | show | jobs
by eldude 4443 days ago
> Up until recently that was pretty much all we had.

[Edit: see my comment below[0]. This is more a coincidence of wording than a StrongLoop marketing line]

When StrongLoop talked at my south bay node.js meetup group, BayNode[1], at Hacker Dojo last month, they demoed Zone.js. Before demoing though, they asked if anyone in the group had "solved this" to which I made it very clear that, "Yes, I did about 2 years ago with trycatch[2]." Their response could be summed up as, "Oh?"

Long story short, not only does my async try/catch library solve this, I can say with near certainty that it solves it in a better, more consistent, more tested, more battle proven, more performant manner. We use trycatch at LinkedIn and have not had to worry about async error handling since.

Additionally, adding it to any control-flow of your choice is trivial, as I have done with my stepup library[3]. Further, their main bullet-points are about enforcing the callback contract, something EVERY control-flow library should be doing, (I previously went into more detail here[4]) and the primary reason for the popularity of promises since they formalized this contract.

In fact, I teach these core contract rules in my monthly week-long node.js bootcamp I give here at LinkedIn[5], and the only thing they have to do with control-flow is that your control-flow library of choice should enforce them, as stepup and promises do. I do add a few rules:

* Function that takes 2 arguments: 1. first argument is an error, 2. second argument is the result, 3. Never pass both, 4. error should be instanceof Error

* Must never excecute on the same tick of the event loop

* Must be passed as last argument to function

* Return value is ignored

* Must not throw / must pass resulting errors

* Must never be called more than once

Long story short, domains are broken, try/catch is insufficient, use trycatch because I solved this problem over 2 years ago and have been perfecting it since.

[0] https://news.ycombinator.com/item?id=7598983

[1] http://www.meetup.com/BayNode/

[2] https://github.com/CrabDude/trycatch

[3] https://github.com/CrabDude/stepup

[4] https://news.ycombinator.com/item?id=7020054

[5] https://gist.github.com/CrabDude/10907185

2 comments

The article only covered error handling, but Zones are a lot more powerful than that. They are nestable (forkable), they can store arbitrary values, intercept microtasks, timers, wrap closures to be associated with the Zone, and a few more things.

Then the key part in Dart is that all of the APIs that invoke callbacks based on external events run the callbacks in the Zone they were registered in. This is what allows Zones to be used to easily run code at the beginning or end of every event loop turn.

> They are nestable

trycatch is nestable as well.

> they can store arbitrary values, timers

Nice. I am currently decoupling trycatch's hooking layer to allow for this arbitrarily[1]. The continuation-local-storage library[2] allows for this functionality as well.

> intercept microtasks

Care to elaborate?

> wrap closures to be associated with the Zone

Yup, similar to domains, though I do wonder when this is necessary? One use case that came up with trycatch was finally support, or the need to exit the current domain/trycatch context.[3]

Lastly, there's one consistent failure I see in all these domain-like, async listener-like, long-stack-trace, event-source modules and that's long-lived resources or how they incorrectly handle EventEmitter handler's context[4], with the core issue being the boundary at which the hook is applied (From Trevor Norris' comment):

    After thinking this over, it occurred to me that trycatch is a top down approach. Whereas AsyncListener is bottom up.
Long story short, things like keep-alive sockets will retain a domain/context/zone(?) and their handlers will be called with the incorrect context.

Do you fix this in your zone.js implementation?

[1] https://github.com/CrabDude/trycatch/issues/38

[2] https://github.com/othiym23/node-continuation-local-storage

[3] https://github.com/CrabDude/trycatch/issues/37

[4] https://github.com/CrabDude/trycatch/issues/32

>> They are nestable > trycatch is nestable as well.

By nestable I mean that you can fork a Zone, configure different values and handlers (for things like intercepting microtasks and timers), and run some code in the forked Zone. All async callbacks spawned from that code will run in the forked Zone.

>> intercept microtasks > Care to elaborate?

Dart has an API for scheduling microtasks inside the event loop: scheduleMicrotask(callback). Zones can intercept this call to do things like keep track of the size of the queue and do something when it empties, or manually and synchronously execute the tasks for controlling time in tests.

>> wrap closures to be associated with the Zone > Yup, similar to domains, though I do wonder when this is necessary?

It's useful for interacting with external systems and preserving Zone affinity. This is how dart:html ensures that event subscription callbacks are run in the correct Zone, it wraps callbacks (only if necessary - if there's an installed Zone) in the Zone and then hands them to the browser. The wrapper installs the correct Zone before executing the callback.

> Long story short, things like keep-alive sockets will retain a domain/context/zone(?) and their handlers will be called with the incorrect context. > > Do you fix this in your zone.js implementation?

Zone.js is a port of Dart's Zone, so I don't know how faithfully it reproduces it. In Dart, I don't know of any API that doesn't execute callbacks in the correct Zone, except for a bug in dart:js that's being worked on.

This seems really cool! I'm surprised I haven't heard about this until now.

However, this solution seems to be Node specific. The example where they lament about how this "was pretty much all we had" was about a browser error. Angular's Zone.js seems to be the closest project to solving the problem in that context.

It's not StrongLoop marketing. I wrote the article and also haven't heard about your modules. I try to stay up to date with NPM (running http://npmawesome.com/) and unfortunately completely missed your work :(
Ah, sorry then for my strong rebuke. I am making the incorrect assumption then that this was a StrongLoop marketing line, not a coincidental similarity.
You should write a blog post about this. There are a lot of parallel efforts going on to bring sanity to async errors in JS, and it would be great to see what the outcome of cross-pollinating these ideas would be.