An analogy I like for the "language support" part is Python generators. All you need to do to turn a regular function into an async one is put the `yield` keyword where appropriate. Promises, are less worse then continuation passing style but they still require you to rewrite all your code using the promise library instead of reusing existing language constructs.
If you want to carry the analogy even further generators can also implement coroutine patterns, if you use yield as an expression (for communication) and yield from to do nested generators.
See http://taskjs.org/ for how it could work in ES6.