3 ms·
Nope, they're completely different. In OP's second example, each caller function stays on the stack until its next() returns, thus the stack keeps growing in s
by findjashua 12y ago
Nope, they're completely different.
In OP's second example, each caller function stays on the stack until its next() returns, thus the stack keeps growing in size.
In async functions, the caller is thrown off the stack once it hands off the callback to the event loop. This is why a callback can't return values or throw exceptions.
- cwmma 12y ago* shouldn't throw exceptions
- mattdw 12y agocan't throw exceptions that the caller can catch. If an exception falls in the forest, and there's no one there to catch it…
- russell_h 12y agoThe problem is that this forces programmers to tightly couple interfaces and implementations. Take for example a cache interface that wraps multiple implementations. The cache might be in-process or it might be a centralized memcached, etc. In order to support both of these, the "get" method must take a key and a callback. But the most reasonable in-process implementation actually grows the stack before calling the callback, while the other implementations reset it. If you iterate a large list of keys, you'll blow the stack with the in-process implementation. So you end up doing things like "setImmediate()" on every get to reset the stack. The "async" library has a neat trick to detect if the callback is called without deferring to the event loop, in which case it does the deferral itself. But in general, programmers are forced to think about these kinds of problems constantly, or hit weird bugs. For example, I once had a periodic task that iterated every account in the database. It began crashing when our database client began returning larger batches, causing iteration not to defer to the event loop.