Skip to content

Instantly share code, notes, and snippets.

@mraleph
Forked from creationix/coroutine-example.js
Created November 14, 2011 16:35
Show Gist options
  • Save mraleph/1364383 to your computer and use it in GitHub Desktop.
Save mraleph/1364383 to your computer and use it in GitHub Desktop.
Shallow coroutines based on Harmony generators
// Variant of Tim Caswell's "fibers" proposal based on Harmony generators.
// Make generator into a shallow coroutine.
function GF(g) {
var f = g(resume);
function resume (value) { f.send(value); }
f.next();
}
function readfile(filename, next) {
GF(function* (resume) {
var err, fd, stat, chunks;
console.log("opening...");
// This is a normal async function. It doesn't know anything about coroutines.
// The FS.open call is non-blocking, even for this coroutine
// Destructuring assignment, wait returns the arguments that resume got.
// The call to wait will suspend this coroutine and only resume when the
// `resume` callback eventually gets called.
[err, fd] = yield FS.open(filename, "r", "0644", resume);
if (err) { next(err); return; }
// Same thing, but doing a fstat on the fd
console.log("fstatting...");
[err, stat] = yield FS.fstat(fd, resume);
if (err) { next(err); return; }
// Here is an example using a blocking loop to read a file in chunks
console.log("reading...");
var chunk, length, offset = 0;
do {
[err, chunk, length] = yield FS.read(fd, offset, 72, resume);
if (err) { next(err); return; }
chunks.push(chunk);
offset = offset + length;
} while (length);
console.log("pausing...");
// Works for other async functions too, not just node ones.
// Sleep this coroutine for 500ms
yield setTimeout(resume, 500);
console.log("closing...");
[err] = yield FS.close(fd, resume);
if (err) { next(err); return; }
next(null, chunks, stat);
});
}
@creationix
Copy link

Nice, update the comments and gist description and it will make more sense to others.

@mraleph
Copy link
Author

mraleph commented Nov 14, 2011

@creationix done.

@kriskowal
Copy link

Harmony generators add generator.throw(error), like send, but effecting an exception at the yield. The proposal also adds support for return values from generators; if a generator halts at an explicit return, a ReturnValue exception inherited from StopIteration is thrown with the exception.value of the return.

This is a function similar to Vyacheslav’s GF: https://github.com/kriskowal/q/blob/8ff517e193185b100feb881185957a7f211b4c72/q.js#L546-602

It is a simple decorator that turns a generator into a promise-returning function and yields on promises. If the promises are rejected, they get propagated as exceptions. The return value of the generator resolves the returned promise.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment