for (var v in nantoka()) yield v とか書かなくちゃいけなくね問題
案外そうでもなかったかもしれない。一個一個の関数を扱いにくいジェネレータ関数のまま放っておくのではなく、継続を引数にとる普通の非同期関数化してしまえばいいんだ。
お題は、これを出力するたびに0.1秒のウェイトいれるようにかえるというもの
function a() { for (var i = 0; i < 3; i ++) { console.log("a"+i); } } function b() { for (var i = 0; i < 3; i ++) { console.log("b"+i); } } function main() { a(); b(); } main(); console.log("done");
runnable関数はKazuho@Cybozu Labs: JavaScript/1.7 で協調的マルチスレッドより
function runnable(generatorFunc) { var generator; var resume = function (value) { try { generator.send(value); } catch (e if e instanceof StopIteration) { } }; generator = generatorFunc(resume); resume(undefined); } function a(cont) { runnable(function (resume) { for (var i = 0; i < 3; i ++) { console.log("a"+i); setTimeout(resume, 100); yield; } cont(); }); } function b(cont) { runnable(function (resume) { for (var i = 0; i < 3; i ++) { console.log("b"+i); setTimeout(resume, 100); yield; } cont(); }); } function main(cont) { runnable(function (resume) { a(resume); yield; b(resume); yield; cont(); }); } main(function () { console.log("done"); });
まあこうするぐらいだったらdeferred-generatorの方が洗練されてるかなー
var a = Deferred.generator(function () { for (var i = 0; i < 3; i ++) { console.log("a"+i); yield Deferred.wait(0.1); } }); var b = Deferred.generator(function () { for (var i = 0; i < 3; i ++) { console.log("b"+i); yield Deferred.wait(0.1); } }); var main = Deferred.generator(function () { yield a(); yield b(); }); main().then(function () { console.log("done"); });
ちなみに普通のDeferredライブラリ (ここではMochiKit) を使うとこう
var Async = MochiKit.Async; function a() { return loop(0); function loop(i) { if (i >= 3) return Async.succeed(); console.log("a"+i); return Async.callLater(0.1, loop, i + 1); } } function b() { return loop(0); function loop(i) { if (i >= 3) return Async.succeed(); console.log("b"+i); return Async.callLater(0.1, loop, i + 1); } } function main() { var deferred = Async.succeed(); deferred.addCallback(a); deferred.addCallback(b); return deferred; // return a().addCallback(b) でもいいんだけど気分的にaとbは同じ書き方で並べたい。 } main().addCallback(function () { console.log("done"); });