There have been some different attempts to expand JavaScript syntax to make this style of programming more elegant.
Narrative JavaScript http://www.neilmix.com/narrativejs/doc/ has a single construct, the arrow which turns everything after the arrow into a closure which is passed as an argument.
The really-real problem that Node.js has is that once they admit that this is a good idea, huge swathes of the Node.js value proposition go flying out the window. If Javascript is not up to the task and you need a source rewriter or a really fancy, convoluted library to make non-trivial Node.js apps actually feasible to build, then... why are we in Javascript at all? Why not use a language and runtime where the support for this was baked in from day one and the compiler is the one doing all the hard work, as it should be?
This is why the Node.js hype was such a bad idea. (Don't miss the word "hype". Node.js was not a bad idea, except inasmuch as it encourages one into dangerous areas.) A useful, if limited, project built its community around a foundation of unkeepable promises. Truth is, the need to deal with this problem, and indeed far worse, the email in question should be considered an exemplar of the problem, just wait until you have three sequences of twice the size interacting with each other, is the inevitable outcome of any serious large project written in the manually-decomposed-cooperative-multiprocessing style, not an anomaly. Human brains are not meant to deal with this. It ceases to be a significant advantage over conventional threading pretty quickly.
Basically what this style comes down to is that instead of letting the runtime schedule your threads, and potentially create nondeterminism that kills your program, you manually schedule your threads instead, and instead choke the programmer on the geometric complexity of the scheduling problem. It makes beautiful small examples and demos, and makes easy things easy, but it makes hard things effectively impossible.
It runs in browsers and on V8, and it can access the CommonJS library ecosystem, and it's a nice language in a lot of other ways.
> This is why the Node.js hype was such a bad idea.
Except that the hype wasn't a bad idea. A lot of programmers are playing with something new and interesting, being exposed to new techniques and philosophies, and creating cool things. That sounds like a good idea to me.
> ... it makes hard things effectively impossible.
Those are very cool projects, but the main issue is that their source transformation is pretty aggressive. Until someone comes up with real, usable debugging facilities for those, they're not going to catch on.
I recently attended a presentation on StratifiedJS and it is really cool, but as you say they do some rather aggressive source transformation. You are basically writing in a different language and loading in an interpreter in JS to handle the new language. ObjectiveJ does the same thing. Take JS, extend it and run it through your own interpreter. It still sort-of looks like JS, but isn't.
Not only do you have the overhead of loading in an interpreter but you are also left without good debugging facilities.
CoffeeScript doesn't have this problem because it compiles down to readable JS, so if you're familiar with both CoffeeScript and JS you can just use native JS debugging tools to go at it. It does, however require the programmer to be familiar with both languages, so it's usually not the right choice for writing projects that you can hand off to another team at some later point.
The point about not being able to use 'normal' JS debugging facilities with StratifiedJS (or other 'higher-level' languages compiling to JS) is certainly true, but IMO it is not nearly as bad as it sounds.
Debugging highly asynchronous programs (whether written in 'straight' JS or in a higher-level language) with a 'normal' JS debugger isn't really much help: the callstacks that the debugger spits out in no way correlate to the asynchronous actions that are going on.
Having an abstraction that sits on top of JS, as it is the case with StratifiedJS, gives us the opportunity to write a debugger that spits out stack traces that actually reflect the true causal state of your program logic.
Granted, we don't have such a debugger yet, but we will in the not-too-distant future. What is already working is that StratifiedJS will amend exceptions with the correct linenumber and module name of the original StratifiedJS sources that threw the exception. So you don't have to manually correlate the generated source code with the original SJS source code, like you would need to do in systems that do a more or less 1-to-1 translation to JS.
Then there's jwacs (http://chumsley.org/jwacs/), which does CPS conversion on JavaScript without inventing weird new terms or requiring runtime libraries.
Narrative JavaScript http://www.neilmix.com/narrativejs/doc/ has a single construct, the arrow which turns everything after the arrow into a closure which is passed as an argument.
StratifiedJS (http://www.neilmix.com/narrativejs/doc/) is more rich with a number of new keywords: hold, spawn, wait etc. for asynchronous programming.