先日に開催された、JSDeferred コードリーディング ( Kanasan.JS : JavaScript Workshop in Kansai)のレポートです。
ご参加頂いた皆様、ありがとうございました。
ソースだけなら数百行なので、時間があまるかも知れないと思っていたのですが、 勘違いも甚だしかったです。
最後まで読み進める事が出来ませんでした。
短いライブラリのコードリーディングは初めての企画だったので、色々と反省点がありますが、 以下、気になった所だけ、書いておきます。
JavaScriptはマルチスレッドをサポートしていないので、時々問題が出てきます。
例えば以下のようなコード。3秒のスリープを擬似的に作り出しています。
function foo(){ var t = new Date; while(true){ if( ( (new Date).getTime() - t.getTime() ) > 3 * 1000 ) break; } alert('foo'); } function bar(){ alert('bar'); }
上記のfooを実行している間に、barの実行が出来ません。
これがシングルスレッドであるが故の問題点です。
そこで、この問題を解決するのが、JSDeferredです。
JSDeferredの本質は、Deferredオブジェクトを単方向リスト(Singly Linked List)で繋げて、それをsetTimeout(0)で実行している所にあります。 Deferredオブジェクトは非同期で実行する為のfunctionを受け取ります。
setTimeoutを使う事によって、重い処理を非同期で実行しながら、クリック等のユーザーイベントを挟めるようになります。
wikiの図が分かりやすいので、最初にそちらを見ると、構造を知るための手助けになります。
JSDeferred - CodeRepos::Share - Trac
ここでは、使い方のサンプルを書いてみます。
<script type="text/javascript" src="jsdeferred.js"></script> <script type="text/javascript"> Deferred.define(); function first(){ alert("first"); } function second(){ alert("second"); } function third(){ alert("third"); } function deferredDemo(){ next(first) .next(second) .next(third); } </script> <p> <a href="javascript:void(0)" onclick="deferredDemo()">実行する</a> </p>
上記のdeferredDemo()を実行すると、内部では以下のようなイメージで、DeferredオブジェクトのLinked Listが展開されます。
(new Deferred { next : function(){ setTimeout(function(){ this.callback.ok(); this._next.next(); }, 0); }, callback :{ ok : first }, _next : new Deferred { next : function(){ setTimeout(function(){ this.callback.ok(); this._next.next(); }, 0); }, callback :{ ok : second }, _next : new Deferred { next : function(){ setTimeout(function(){ this.callback.ok(); this._next.next(); }, 0); }, callback :{ ok : third } } } }).next(); //ここで最初のDeferredのnextを実行する。
上記のコードはあくまで、構造のイメージなので、JavaScriptの構文でもなければ、JSDeferredのソース構造とも違う点は注意して頂くとして、 構造の概要をソースで表すと上記のような感じです。
Deferredオブジェクトは、this._nextに新しいDeferredを持つ事で、単方向のLinked Listを実現しています。
イメージとしては、コールバック関数をsetTimeout(0)で実行し、 それが終わったら次のDeferredオブジェクトのコールバック関数を、またsetTimeout(0)で実行する。 という繰り返しで、非同期処理を実現しています。
グローバルのnext()関数と、Deferredオブジェクトのnextメソッドは別物です。 混同しがちだったのですが、コードリーディングの際に知っておくと読みやすくなると思います。
for〜inで新しい書き方を見つけましたので、抜粋します。
http://coderepos.org/share/browser/lang/javascript/jsdeferred/trunk/jsdeferred.jsfor (var i in dl) if (dl.hasOwnProperty(i)) (function (d, i) { d.next(function (v) { values[i] = v; if (--num <= 0) { if (dl instanceof Array) { values.length = dl.length; values = Array.prototype.slice.call(values, 0); } ret.call(values); } }).error(function (e) { ret.fail(e); }); num++; })(dl[i], i);
ループをeachっぽく書いています。
外部ライブラリを使わずにforeachのようなループの書き方をしたい時に使えそうです。
JavaScript 1.6からはforEachが使えますが、クロスブラウザを考慮する時は使えないので、上記のような書き方は面白いと思います。
JSDeferredを使う時は、"parallel"、"wait"、"next"、"call"、"loop"という、とても分かりやすいfunctionだけ覚えればいいので、 使う分にはとても楽です。
但し、内部的にはこれが複雑に見える要因にもなり、window.next()とDeferred.next()の違い、 Deferred.prototype.nextとDeferred.nextの違い等が、コードを読みにくくする一因にもなっています。
プロトタイプのオブジェクト指向を学ぶ上では、prototypeの使い方のお手本にはなると思います。
個人的には他にも、Deferred.callとネイティブメソッドのFunction.callが混同してしまいました。
上記のような事から、APIとして使う変数名は分かりやすくても、 内部の命名が分かりにくいという意見がちらほら聞かれました。
時間切れで途中までしか読めませんでした。
今の所の結論としては、Deferredオブジェクトを拡張する為にregisterメソッドというのがあるのですが、 そこでしか使われれていない事から、Prototype.jsのbind()のようなイメージで引数の束縛をしているのだと思います。
今回はTechTalkの時間が多すぎて、本編の時間を圧迫してしまった事が反省点の一つでした。 次回以降は気を付けたいと思います。
私37toはどこにも告知していなかった、flickwriterというGreasemonkeyを紹介しました。
Firefoxの拡張、Make Link :: Firefox Add-onsの Flickr版とも言えるGreasemonkeyです。
Flickrの写真ページから、各写真サイズのリンクを簡単に取得する事が出来ます。
DQWindowManagerの紹介。
DQWindowManager - Webをドラゴンクエストっぽく遊ぼう!
一言で言うと、ドラクエ風のウィンドウメニューを作れる。
それだけでも、ドラクエが好きな人には十分なのですが、 なんとプレゼンが出来たり、どっかのサイトのブックマークレットを拾って、 自分のメニューに加える事が出来たりします。
サーバーサイドも含めてのサービスなので、ユーザーだけ集まれば、とても面白い事が出来ると思う。
たとえば、今同じページを見ている人が、ページ内をうろうろしていたり、 その人にメッセージを送ったり等々。
最近は開発が止まっているようですが、とても面白いサービスだと思いました。
Lingrでも使われていたプッシュ配信技術、「Comet」を利用した「Comets」の紹介。
Sixeight's comets at master - GitHub
実用的にはまだ達していないとの事でしたが、サーバー側のソースは100行程のようで、 Comet実装のサンプルとしては、非常に良い題材と思いました。
会場では、運用レベルになるとやはり同時接続数、ポートの枯渇が問題になってくるという話が出ていました。
Stack Stock BooksのAPI + jQuery + Rubyを使ったサービスの紹介。
JavaScriptでインクリメンタル検索のライブラリ(jQueryのプラグインかな?)が動かないという話が出ていたのですが、 その場で参加者からいくつもの解決案が出てきました。
こういうケースを見てると、とりあえず発表してみるのは重要だと感じました。
発表を躊躇している方々も、気負いせずに軽いタッチで発表してもらえると、嬉しい限りです。
「あじと」いう居酒屋にて。
たまたま席順が学生とその他で席が分かれてしまい、ジェネレーションギャップを感じていました。
私自身が端っこに座っていた事もありますが、もう少し全体を盛り上げる為の気遣いが足りなかったかなと、反省しています。
Lingrに依存していた勉強会は、移行先に四苦八苦されていると思いますが、 Kanasan.JSでは、Web上でSkypeのチャットが出来る、SkWebChatを使ってみました。
SkWebChat(Webで使えるスカイプチャットサービス)
IRCやSkypeのグループ(最新版Winクライアントでは、オープンチャットが使えない)、 他にはTwitterやWassrも検討していましたが、以下の点からSkWebChatを選びました。
誰でも発言出来るという点が良かったです。
ただ、終わってみると発言がいつもより少ないのが気になりました。
コードリーディングが難解だからか、チャットのUIがLingr程よくはないからかは分かりませんが、 もう少し様子を見ようと思います。
本命はGoogle Waveなので、今からサービスインを楽しみにしています。
今回は初めての会場でした。
少し会場費が高いのですが、従業員の方の対応がとても良かったです。
LANも問題なく繋がり、京橋の近くなので交通の便もよく、とても良かった。
会場費は少し高いのですが(空調機を使うと30%増し。備品は安いほうかと)、LANが必要な会場の候補としては良さそうです。
入ると湯のみが人数分置いてあり、お茶がサービスで出ました。
従業員の方の対応が良かったからか、また使いたいなと思いました。
最後になりますが、ご参加頂いた方々、ありがとうございました。
今回は特にid:yaottiと、 id:Sixeightの両スタッフの助けが無ければ、 開催出来なかったと思います。とても助かりました、ありがとうございました。
Posted at 37to : commetns(0) : trackbacks(0)
本エントリへのトラックバックURL
http://blog.37to.net/mt/mt-tb.cgi/117