Created
November 8, 2011 22:14
-
-
Save creationix/1349451 to your computer and use it in GitHub Desktop.
Lua style coroutines in nodeJS proposal
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var FS = require('fs'); | |
var Fiber = require('./fiber'); // Not to be confused with the existing node-fibers module | |
// readFile is a normal non-blocking, async function, but internally it can use | |
// the coroutine helper fiber. These kinds of coroutines are no more dangerous | |
// to the caller than any other async function. | |
function readfile(filename, next) { | |
// The call to Fiber is non-blocking. It's contents are only run sync till | |
// the first call to wait and then it returns. | |
Fiber(function (resume, wait) { | |
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 | |
FS.open(filename, "r", "0644", resume); | |
// 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] = wait(); | |
if (err) { next(err); return; } | |
// Same thing, but doing a fstat on the fd | |
console.log("fstatting..."); | |
FS.fstat(fd, resume); | |
[err, stat] = wait(); | |
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 { | |
FS.read(fd, offset, 72, resume); | |
[err, chunk, length] = wait(); | |
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 | |
setTimeout(resume, 500); | |
wait(); | |
console.log("closing..."); | |
FS.close(fd, resume) | |
[err] = wait(); | |
if (err) { next(err); return; } | |
next(null, chunks, stat); | |
}); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// This is the implementation of the fiber helper used in the example. | |
// 'coroutine' is a made up addon or builtin to future javascript | |
// that implements lua style coroutines. | |
var Coroutine = require('coroutine'); | |
module.exports = function Fiber(fn) { | |
var resume = Coroutine.wrap(fn); | |
resume(resume, Coroutine.yield); | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
It looks like this is just as easy to implement with generators, which will almost certainly make it into future versions of v8, so this is probably going to be a viable strategy for future modules.
https://gist.github.com/1364503