JavaScriptのジェネレータについて思うこと
追記 (2014/3/21)
以下がこの記事に対する自分の答えになります
JavaScriptにジェネレータってあるじゃないですか。それを使えば非同期の処理を同期みたいに書けるっていうのがあるじゃないですか。
function myroutine() { なんかする1; yield 1000; なんかする2; yield 2000; なんかする3; yield 1000; なんかする4; } function run_routine() { var g = myroutine(); (function() { try { var msec = g.next(); } catch (e if (e instanceof StopIteration)) { return; } setTimeout(arguments.callee, msec); })(); }
でもねーこれmyroutineを複数の関数に分割とかしたらそのままじゃ動かないじゃないですか
function myroutine() { myroutine_inner_A(); yield 2000; myroutine_inner_B(); } function myroutine_inner_A() { なんかする1; yield 1000; なんかする2; } function myroutine_inner_B() { なんかする3; yield 1000; なんかする4; }
これをどうにかするためにはmyroutine_inner_A, myroutine_inner_Bを呼ぶときにforを使わないといけない
function myroutine() { for (var v in myroutine_inner_A()) yield v; yield 2000; for (var v in myroutine_inner_B()) yield v; }
Luaのコルーチンだと普通に複数の関数に分割できるんだけどなー
function myroutine() myroutine_inner_A() coroutine.yield(2000) myroutine_inner_B() end function myroutine_inner_A() なんかする1 coroutine.yield(1000) なんかする2 end function myroutine_inner_B() なんかする3 coroutine.yield(1000) なんかする4 end
でcoroutine.yieldってのはJSのyieldと違って単なる関数にすぎないのでコールバックとして渡すこともできる
だから以下のようなことも出来るはず! (LuaにはsetTimeoutなんてないので実際には動かないですけど)
function myroutine(wait_func) (wait_funcを指定ミリ秒待つ関数として使ってなにか実装) end function run_routine() local co = coroutine.create(function() myroutine(coroutine.yield) end) local function loop() local _, val = coroutine.resume(co) local status = coroutine.status(co) if status == "dead" then return end setTimeout(loop, val) end loop() end
JavaScriptもこれぐらいできれば非同期処理を同期っぽく書けるって言われて納得できるんだけど、今のジェネレーターの機能だけじゃあ納得できない。
ずっともやもやしていたので記事にしてみました。
ツッコミ歓迎。