yieldを使って非同期->同期(続き)
元ネタ:
http://labs.cybozu.co.jp/blog/kazuho/archives/2007/05/coopthread.php
これを見て書いたエントリ:
http://d.hatena.ne.jp/shinichitomita/20070525/1180106472
上のエントリは、実装前とはいえかなり大間違いなスクリプト書いてる。何やってるんだか。
とりあえず先のエントリのコメントで「for ループの中でyield使えばできる」とわざわざもらったので、ちょっとやってみる。
/** * del.icio.usのJSONP呼び出し。非同期でコールバック関数に値が呼び戻される。 */ function getDeliciousNetwork(id, callback) { var url = 'http://del.icio.us/feeds/json/network/'+id; jsonp.invoke(url, callback); } function getDeliciousPosts(id, callback) { var url = 'http://del.icio.us/feeds/json/'+id; jsonp.invoke(url, callback); } /** * 非同期コールバックを引数の最後にとる関数を同期化する。 */ Function.prototype.synchronize = function(next) { var _orig = this; return function() { var args = Array.prototype.slice.apply(arguments); var obj = {}; _orig.apply(this, args.concat(function(data) { obj.value = data; next(); })); return obj; } }
で、元ネタのrunnable関数はそのままで、こんな感じで実装。
runnable(function(next) { var getDeliciousNetworkSync = getDeliciousNetwork.synchronize(next); var getDeliciousPostsSync = getDeliciousPosts.synchronize(next); var network = getDeliciousNetworkSync('stomita'); yield; network = network.value; for (var i=0; i<network.length; i++) { var posts = getDeliciousPostsSync(network[i]); yield; print(posts.value); } })
終わったあとにStopIterationなんちゃらのExceptionが出るけどまあ無視。
上記のrunnableみたいなやつでプロセスを外側から囲わなければ駄目な点と、yieldの後にわざわざ値を取り出す作業が必要というところ(これは巧くできないかな?)、そしてやっぱりyieldが表に出てしまうのが微妙に美しくない気がするのは、多くを求め過ぎ?