Was reading a little about task.js today. The tl;dr they give is that "generators + promises = tasks", i.e. the combination of the coroutine support that's in ES6 (generators) plus either library-based or baked-in promises should give you a nice concrete syntax for kinda-sorta pretending that asynchronous calls are synchronous function calls.
However I got to thinking it doesn't actually depend on most of what people use promises for in the status quo of going through contortions to avoid CPS-converting all your javascript programs. (As an aside, much as I find js comfortable for some bizarre reason given my academic upbringing, I gotta say, it seems pretty ludicrous at times to actually do "the node.js thing" with code. Direct-style 4 lief.) Specifically the .then-chaining that a typical library like Q provides doesn't seem necessary for the promises that get yielded across coroutines.
Seems like I can just do the following: (in a recent firefox or chrome after you go into about:flags and turn on "experimental javascript features" or node 0.11.6 with the --harmony flag)
(and here's the ocaml I wrote just to keep the types straight in my head:
However I got to thinking it doesn't actually depend on most of what people use promises for in the status quo of going through contortions to avoid CPS-converting all your javascript programs. (As an aside, much as I find js comfortable for some bizarre reason given my academic upbringing, I gotta say, it seems pretty ludicrous at times to actually do "the node.js thing" with code. Direct-style 4 lief.) Specifically the .then-chaining that a typical library like Q provides doesn't seem necessary for the promises that get yielded across coroutines.
Seems like I can just do the following: (in a recent firefox or chrome after you go into about:flags and turn on "experimental javascript features" or node 0.11.6 with the --harmony flag)
function Prom() {
var self = this;
this.then = function(k) { self.reso = function(x) { k(x); }; };
this.reso = function(x) { self.then = function(k) { k(x); }; };
}
function spawn(task) {
var gen = task();
(function go(x) {
var s = gen.next(x);
if (!s.done) s.value.then(go);
})();
}
function slow(v, t) {
var p = new Prom();
setTimeout(function() { p.reso(v); }, t);
return p;
}
spawn(function*() {
var counter = 10;
while(counter--) {
var x = yield slow("a", 59);
console.log(x);
}
});
spawn(function*() {
var counter = 10;
while(counter--) {
var x = yield slow("b", 100);
console.log(x);
}
});
(and here's the ocaml I wrote just to keep the types straight in my head:
let prom () = let rec reso = ref (fun x -> next := fun k -> k x); and next = ref (fun k -> reso := fun x -> k x) in (reso, next);;)