Most importantly - generators don't compose.
(I'm talking about python-style generators, the type of generators javascript adapted.)
To give you an idea of what I mean:
second_sound = coroutine(function() {
yield;
console.log('Tick!');
yield;
console.log('Tock!');
});
hour_sound = coroutine(function() {
yield second_sound();
console.log('Ding dong!')
});
It's pretty obvious what programmer wants to achieve. But with generators you can't call "yield" from deeper-level function - generators are one-level-deep. The only way to compose is to 'yield' a new (deeper) generator. At this point, the caller of hour_sound() needs to understand what to do if the callee returns a generator, instead of 'null' or a valid value. And it needs to run this "deep" generator before doing 'send' on the hour_sound again.This is just the beginning of the mess. Errors get very hard to track as tracebacks get completely unreadable. It's not easy to decide what to do when one of the nested generators throws an exception.
Python frameworks went through this long time ago, see here (look especially for the "yield" keyword): http://www.tornadoweb.org/documentation/gen.html
Here's a bit of the underlying logic of this "simple" "coroutine-programming-syle" layer of tornadoweb: http://www.tornadoweb.org/documentation/_modules/tornado/gen...
And here's more! https://github.com/facebook/tornado/blob/master/tornado/gen....
All this magic is heavily based on the way python exceptions are integrated with generators, for example one can try to catch "StopIteration" to do a cleanup within generator. I doubt this is possible in javascript as the exceptions mechanism is much less mature.
Edit: Don't get me wrong - I love generators! But one-level-deep generators are not coroutines with stack that can be "blocked" from any deeper function.