Writing code that does async I/O is a total pain in the ass. And I’ve written a whole lot of async I/O code, so I should know.

However, if you’re working in a language with full support for continuations it is a lot easier. JavaScript doesn’t support continuations fully, but it has generators, which is like a lite-version of continuations. That is part of the reason why I’m interested in JavaScript scripting.

So, I’ve been experimenting with how to bind GIO-style async operations in JavaScript so that its easier to write async I/O code. I’ve got something going now that looks pretty ok.

Here is an example that calls an async function “$open” to read three files. It also demonstrates how to do calls from one async generator to another.

do_stuff = new AsyncRunner (function (filenames) { for (let i in filenames) { var data = yield $open (filenames[i], 0); print ("data for " + filenames[i] + " = " + data); } var ret = yield do_stuff2.call("other.txt"); print ("AsyncRunner call returned: " + ret); });

do_stuff2 = new AsyncRunner (function (filename) { var data = yield $open (filename, 0); print ("data for " + filename + " = " + data); yield "the end (of do_stuff2)" });

do_stuff.start(null, ["test.txt", "test2.txt"]);

Its IMHO pretty easy to understand. At every async op we yield which suspends execution and restarts it at that point when we have the operation results. The “$” in “$open” is just to make it different from the sync variant and still short.

This code is far easier than it would look in C, where we would have to split out a new function at each async function call. The loop in do_stuff makes this quite tricky to do.

The code that implements this is here. Its somewhat complicated, using things like currying, closures and generators, so read it carefully.

I’d like some feedback on this. Are there any tricks I’ve missed that could make this nicer? I really wish javascript had a macro facility so that the yield keyword could be put inside the async calls and we could avoid the boilderplate around the AsyncRunner creation. I would also like to make the AsyncRunner objects callable like “do_stuff2()”, but that doesn’t seem possible with standard javascript (although it is the AsyncRunner class is implemented natively via the spidermonkey APIs…)