[ANN] copromise

240 views
Skip to first unread message

Dean Landolt

unread,
Aug 30, 2014, 5:09:46 PM8/30/14
to nod...@googlegroups.com
I was trying to find a clean way to adapt co to be able to be able to yield promise or non-promise values (e.g. use yield like the `when` method of a lot of promise libs), so I started hacking out features. By the time I was through I was pretty surprised to see that it essentially boiled down to this little block of code (assuming es6 promises):

function run(coroutine) {
return new Promise(function (resolve, reject) {
(function next(value, exception) {
var result;
try {
result = exception ? coroutine.throw(value) : coroutine.next(value);
}
catch (error) {
return reject(error);
}
if (result.done) return resolve(result.value);
Promise.resolve(result.value).then(next, function(error) {
next(error, true);
});
})();
});
}

This allows you to yield any promise or non-promise value, and returns a promise representing the result. You can also use `yield*` to delegate to other coroutines correctly.

If anyone's interested I wrapped this up and published it to npm as the `copromise` module. Enjoy!

Floby

unread,
Sep 1, 2014, 4:43:36 AM9/1/14
to nod...@googlegroups.com
Hello, this seems rather useful. I'll give it a 9/10.

to get a 10/10, name it compromise instead :D

Jonathan Ong

unread,
Sep 2, 2014, 7:30:27 PM9/2/14
to nod...@googlegroups.com
i don't get it. co already allows yielding promises. 

Dean Landolt

unread,
Sep 4, 2014, 1:49:57 AM9/4/14
to nod...@googlegroups.com
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).


--
Job board: http://jobs.nodejs.org/
New group rules: https://gist.github.com/othiym23/9886289#file-moderation-policy-md
Old group rules: https://github.com/joyent/node/wiki/Mailing-List-Posting-Guidelines
---
You received this message because you are subscribed to the Google Groups "nodejs" group.
To unsubscribe from this group and stop receiving emails from it, send an email to nodejs+un...@googlegroups.com.
To post to this group, send email to nod...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/nodejs/79c78a3d-b3a9-4e99-ab60-dded283dc132%40googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

pixel67

unread,
Sep 11, 2014, 3:32:59 AM9/11/14
to nod...@googlegroups.com
Nice
Reply all
Reply to author
Forward
0 new messages