Spion writes about JavaScript and Node.js, mainly async patterns, promises versus callbacks, and their performance and debugging tradeoffs.
HN commenters cite it in discussions of promises, bluebird and async/await, and link the post on promises plus generators as a way to avoid callback hell.
"the debugging story for generators is somewhat bad, especially because of the missing stack traces for thrown errors. Fortunately, there are solutions and workarounds, like those implemented by genny (obtrusive, reduces performance) and galaxy (unobtrusive, but requires native modules)."
From the post you brought up, http://spion.github.io/posts/analysis-generators-and-other-async-patterns-node.html -- by the author of Genny. As I said, that's at least qualitatively the same as Q; quantitatively I haven't looked. At https://github.com/spion/genny there's the example line
require('genny').longStackSupport = true
and "This results with CPU overhead of approximately 500% and memory overhead of approximately 40%. In the future, the overhead will probably be eliminated in node but not in browsers." The benchmark post says Catcher is worse.
The README for Q shows the same switch and says "This feature does come with somewhat-serious performance and memory overhead,
however. If you're working with lots of promises, or trying to scale a server
to many users, you should probably keep it off. But in development, go for it!"
I'm not a current user of any of these systems, but this is why I said the first-order cause of any performance difference appears to be that ClojureScript is not a library.
On the topic of using callbacks, promises + generators will enable you to do the same job with almost the same level of performance (see http://spion.github.io/posts/why-i-am-switching-to-promises.html) whilst avoiding callback hell and having to perform error handling in multiple places.
A good Promise library (like https://github.com/petkaantonov/bluebird) even provides mechanisms for writing functions that both return Promises as well as accept callbacks, allowing your API client to choose how they wish to use it.
Also, beware of making a function "asynchronous" by simply having it accept a callback parameter, e.g.:
function myFunc(v, cb) {
someOtherObject.v = v;
cb();
}
myFunc(5, function(err) {
if (err) return console.error(err);
console.log('call done');
});
console.log('call started');
In the above code, you'll see "call done" before you see "call started" because myFunc() isn't really functioning asynchronously.
This is yet another reason to use a good Promise library like Bluebird, as it ensures that even if you wrap a synchronous function inside a Promise the resulting execution will flow as if it was asynchronous.
Hmm, those are strange results indeed. I would not be surprised if those measurements were made a year ago. Back then, promises were really slow.
But then bluebird came out and changed everything, and many of the other promise libraries followed suit. Most promise libs are now really lightweight (with the only remaining exception being Q).
See https://gist.github.com/spion/6990910 ; http://spion.github.io/posts/why-i-am-switching-to-promises.html ; https://github.com/spion/async-compare/blob/master/latest-results.md -
For example, bluebird (and most other promise libraries today) have 2 to 3 times lower overhead than caolan's async and are comparable to the most hand-optimized raw callbacks.
Have you looked into bluebird[1]? It and most of the available promise libraries have a nodify-esque function where you can simple do this:
var fs = Promise.promisifyAll(require("fs"));
And all of the regular methods in fs are now promisable. Q also seems to be one of the slowest[2] promise libraries there is. I'm not sure why so many people use it. That guy has a rather large benchmark table from a couple months ago as well and Q seems to be shockingly slow compared to the dozen or so other promise libraries out there.
1. https://github.com/petkaantonov/bluebird
2. http://spion.github.io/posts/why-i-am-switching-to-promises.html
Async await while looking nice compared to bare callbacks and Promises are still not without drawbacks. For example one cannot use await inside nested callback so it's in async functions it's necessary to use for-of and avoid forEach when dealing with Promise values.
* http://journal.stuffwithstuff.com/2015/02/01/what-color-is-your-function/
* https://spion.github.io/posts/es7-async-await-step-in-the-wrong-direction.html
Current solution is just an evolutionary change merging generators and Promises.
There's https://github.com/zenparsing/es-typed-catch to solve the problem I raised here 3 years ago: https://esdiscuss.org/topic/try-catch-conditional-exceptions-in-light-of-generators and there's a good writeup on problems with async/await by fellow bluebird contributor Gorgi Kosev (spion) here: https://spion.github.io/posts/es7-async-await-step-in-the-wrong-direction.html (Although I don't really agree with it)