I’m excited to announce the latest version of jsTask, which now supports first-class, synchronizable events. A Sync object represents an event that may or may not have fired yet, and which a task can block on.
jsTask already makes it easy to write tasks that block on I/O:
var foo = yield read("foo.json");
var bar = yield read("bar.json");
But the power lurking behind that code is the fact that read actually returns a Sync value, which can be used to build more interesting synchronizable events. For example, we can do a join on several concurrent operations, so that one doesn’t have to wait for the other before initiating:
var [ foo, bar ] = yield join(read("foo.json"), read("bar.json"));
Or we can choose from several different concurrent operations, letting whichever completes first produce the result (and cancelling the others):
var file = yield choose(read("a.json"), read("b.json"), read("c.json"));
With combinators like these, you can start to build interesting idioms, such as the timeout method, which I went ahead and built in to the library:
try {
var file = yield read("foo.json").timeout(1000);
} catch (e) {
// I/O error or timed out
}
This is just the beginning: I’ll be implementing Sync wrappers for all the major DOM I/O events, and I’ll keep experimenting with API’s for common use cases and helpful idioms.
I believe jsTask would also be useful for server-side JS frameworks like node.js, which use non-blocking I/O heavily. But first we have to get generators into V8 and ECMAScript!
…or get spidermonkey running in Node.js…
Thanks for this library! =) I especially like the look of the concurrent operations examples.
I’m interested to know what you think of this approach in regards to performance ? Async non-blocking I/O obviously has inherent performance benefits with JS being single threaded in that other operations can continue. Does overuse of this library risk wasting CPU cycles or am I missing something ?
For example with Node much of its famed performance, apart from V8 awesomeness, comes from its non-blocking/async approach. Do you suggest using it for only some of non performance critical server-side code ?
I’m not saying jstask is a bad idea, I’m just trying to understand the best use-cases for it esp regarding any impact on performance.
Right on! This looks very similar to what Havoc Pennington has proposed and is implemented in my Stick framework. I full-heartedly agree about getting generators into V8 and ES.
Have you seen Reactive Extensions (Rx) for Javascript? The what jsTask does is at the core of Rx
http://msdn.microsoft.com/en-us/data/gg577609
Can you comment on the differences in the design and/or goals?
@Isaac: You certainly can abuse the library by blocking program logic unnecessarily. But a nice thing is that “blocking” doesn’t actually jank the browser event queue; it only blocks your one task. And another nice thing is that blocking is still very explicit because it always involves the
yieldkeyword. So it’s not possible to accidentally call a blocking API without realizing it.This library should work in conjunction with the non-blocking async approach, not instead of it. Even in Node, you still have operations that can’t continue until they receive results from I/O. This library makes those operations more straightforward to express.
@Hannes: Thanks! I look forward to checking out your Stick framework.
@Chris: Rx is based on a slightly different model than jsTask. Rx’s model is known as functional reactive programming (FRP). The core concept there is a (possibly infinite) stream of events, and you build abstractions by combining/mapping/filtering on streams. Another example of FRP for JavaScript is Flapjax.
jsTask is based on a model that’s a little lighter-weight, where a Sync will typically represent just a single event, rather than a sequence of events. But both models have similarities, in that they try to abstract away the imperative style of event-driven programs. FRP is maybe a little more ambitious; it inverts the control flow of your whole program. But the benefit you get is a vastly simplified control-flow model. I really like Rx and I hope that it continues to pick up steam.
My goal was really just to show that you can get a lot of simplification — particularly to eliminate the nested-callback problem — with maybe a bit less restructuring of your program. But people really should experiment with both styles! There’s no way to know for sure without testing it out on real programs.
@dherman Thank you very much for your helpful response! I am confident I understand how to best utilize this in my projects now. Really appreciate your work on this, it should make certain code far tidier.