Lazyと非同期処理
やばい、おもしろいなあ。こういうのはできれば休日にしてほしいよ。
http://la.ma.la/blog/diary_200702210356.htm
lazy化するところも汎用的に書いたらだめかしらん?
Function.prototype.to_lazy = function() { var orig = this; var args = Array.prototype.slice.apply(arguments); var lazy_object = { isLazy: true, force: function(callback){ orig.receive_lazy().apply( null, args.concat(function(value){ lazy_object.isLazy = false; lazy_object.value = value; callback(lazy_object.value); }) ); } }; return lazy_object; }
lazy化できる関数は、最後の引数にcallback関数をとるものとする。
ためしにdel.icio.usのネットワークをとってくるコード。JSONPなので、基本的にはすべて非同期。
同期の関数は、こちらを参考に非同期化している。
http://d.hatena.ne.jp/amachang/20061129/1164799871
// minimal JSONP Jsonp = { count : 0, callbacks : {}, invoke : function(url, callback) { var count = this.count++; var s = document.createElement('script'); s.type = 'text/javascript'; s.charset = 'utf-8'; s.src = url + (url.indexOf('?') > 0 ? '&' : '?') + 'callback=Jsonp.callbacks._'+count; this.callbacks['_'+count] = function() { delete Jsonp.callbacks['_'+count]; callback.apply(null, arguments) } document.body.appendChild(s); } } function readDelId(callback) { $('delGetButton').onclick = function() { $('delGetButton').disabled = true; callback($('delId').value) } } function getDelNetwork(username, callback) { Jsonp.invoke( 'http://del.icio.us/feeds/json/network/'+username, callback ) } function getDelPosts(username, callback) { Jsonp.invoke( 'http://del.icio.us/feeds/json/'+username, function(posts) { callback({ username : username, posts : posts }) } ) }; function map_async(arr, func, cont) { var count = arr.length; var rarr = new Array(arr.length); if (count==0) cont(rarr); arr.map(function(a, i) { func(arr[i], function(ret) { rarr[i] = ret; count--; if (count==0) cont(rarr); }) }) } function render(networkPosts, cont) { $('result').innerHTML = '<div>'+ networkPosts.map(function(np) { return '<h2>'+np.username+'</h2>'+ np.posts.map(function(post) { return '<a href="'+post.u+'">'+post.d+'</a>'; }).join('<br/>') }).join('</div><div>') + '</div>'; $('delGetButton').disabled = false; cont(); } // function getNetworkPosts() { var id = readDelId.to_lazy(); var networks = getDelNetwork.to_lazy(id); var networkPosts = map_async.to_lazy( Array.slice.asynchronize().to_lazy(networks, 0, 5), getDelPosts ); return render.to_lazy(networkPosts); } window.onload = function() { getNetworkPosts().force(arguments.callee); }
実際に動いているコードはこちらで。
http://www.geocities.jp/stormriders999/lazy_delicious.html