Sure, you can yield a promise in co, along with some other deferred types of things. It's very flexible, but that's precisely the problem. You have to know the type of every value you yield on, or at least know for sure it's one of the deferred types co supports. In copromise you can just `yield` anything, and if it's not a promise, it'll be lifted into one and will resolve on the next turn, just like the `when` function of many promise libs.
This has a number of uses, but I'm particularly interested in how this can be used in combination with for-of syntax in es6 to create elegant lazy streams (iterators that yield chunks as promise values). Here's a function that frames an iterator stream yielding string chunks (lazily as promises or not), and calls some `write` function with each line array it collects up. Who knows if this `write` returns a promise, but if it does, yielding on it automatically exerts backpressure:
copromise(function* () {
var buffer = '';
for (var chunk of stream) {
// split on newlines, awaiting chunk as it could be a promise
var lines = (buffer + (yield chunk)).split(/\r?\n/);
// keep the last partial line buffered
buffer = lines.pop();
// wait for write to finish before next read (applies backpressure)
yield write(lines);
}
// Just handle any leftover
if (buffer) {
yield write([ buffer ]);
}
});
As far as transform streams go this is still more clunky than it has to be, but it's just intended to show a few uses for being able to yield anything (and act as a little teaser for how for-of and coroutines can be used to completely node's wretched stream API).