あけましておめでとうございます。
今年は「P2Pのハイブリッド型アーキテクチャ」に似たアーキテクチャを取るアプリケーションが登場し、「クライアント間の結びつき」がますます強くなるだろう。「ブラウザ上での並列プログラミングやブラウザをノードに見立てたP2Pプログラミング」を可能にする技術に、今年は大きな動きがありそうだ。私は、今年はCometが鍵になるのではないかと考えている。
現在、ブラウザだけではできない事は、
- クロスドメイン間のメッセージ通信
- マルチスレッドのアプリケーション構築
- ストレージへのデータ保存
- Serverからのイベントの通知
1はClient to Clientのメッセージパッシング、4はServer to Clientのイベント通知である。
これらの制約を超えれば、ブラウザ上のプラットフォームはますます強力になる。
Cross-document Messaging
クロスドメイン間のメッセージ通信は、WHATWGがHTML5 で提案しているpostMessageと同様の仕組みをGoogleが実装している。
HTML5のCross-document messagingは、DOM2 イベントモデルと似た方法でメッセージ受信時のリスナを登録する。リスナに渡されるMessageEventオブジェクトには、data, domain, uri等のプロパティを含むので、CSSを防げる。
var o = document.getElementsByTagName('object')[0];
o.contentWindow.postMessage('Hello world');
document.addEventListener('message', receiver, false);
function receiver(e) {
if (e.domain == 'example.com') {
if (e.data == 'Hello world') {
e.source.postMessage('Hello');
} else {
alert(e.data);
}
}
}
GoogleもWHATWGのHTML5のpostMessageと似たメッセージングAPIをGoogle Gearsで提案している。Messaging APIは、portオブジェクトを作成して、listenする。sendMessageでテキストメッセージを送信する。
Cometサーバを利用すれば簡単にクロスドメインの非同期メッセージングを実装できる。ShootingStarを使用してMessaging APIを作った際は、create/subscriberモデルの非同期Messaging APIを次のように設計した。
dojo foundationのCometdは、Bayeux Protocolに基づき実装されている。dojoのクライアントサイドAPIもsubscriber / publisherアーキテクチャである。
var subscriber = createSubscriber('mychannel');
var publisher = createPublisher('mychannel');
subscriber.addEventListener(function(params) {
switch(params.event) {
case 'enter':
log(params.uid + ' entered');
break;
case 'leave':
log(params.uid + ' entered');
break;
}
});
// listener
subscriber.addMessageListener(function(params) {
log(params.uid + ' sent a message. timestamp = ' + params.timestamp);
});
// publish message
publisher.publishMessage({timestamp: (new Date()).getTime()}, tag);
dojo.require("dojox.cometd");
jQuery(function($) {
dojox.cometd.init("http://example.com/cometd");
dojox.cometd.subscribe("/slideshow/change", function(comet) {
$('#currentSlide').attr('src', comet.data.src);
});
});
subscriber / publisher型Messaging APIを使用して多数のクライアントが連携するアプリケーションを構築すると、コードが煩雑になり、デバッグも面倒になる。メッセージパッシングAPIではなく、DOM2 合成イベントと同様にリモートクライアント(別のブラウザ)のイベントやDOMをRemoteEventとしてイベントドリブンでコードを統一できれば美しい。
Server Sent Event(SSE)
Server-sent DOM events
現在、SSEを実装しているブラウザは、Opera 9だけである。その他のブラウザに実装される動きは、今の所ない。WHATWGのSSEは、HTMLEventSourceElementに対して任意のイベントハンドラを指定する。HTMLEventSourceElementは、srcプロパティ一つだけ持ち、Remote Event受信時のイベントハンドラをonmessageで指定できる。srcプロパティには、イベントを通知するURIを指定する。serverはイベントをContent-Type: application/x-dom-event-streamで返す。
Event: server-time
data: [time on the server]
Event: the-answer
data: 42
Event Filedには任意の値を指定できる。Interpreting an event streamで、指定可能なフィールドが列挙されている。指定した値でEventオブジェクトが作成されイベントリスナに渡される。
イベントハンドラはDOM2 イベントモデルと同じである。
<event-source id="event_source" src="/event/timestamp"/>
var es = document.getElementById('event_source');
es.addEventListener('server-time', function(event) {
log('SSE: A server-time event recieved.');
}, false);
Event Streaming to Web BrowsersでSSEを使用したWeb Chatを紹介している。
しかし、HTMLEventSourceElementをOpera9でテストした所、srcに指定したURIをポーリングする挙動を見せた。(ほぼ1秒間隔) Cometとは異なるようだ。(要調査)
Multi Treads
Javascriptは、完全にシングルスレッドで動作するが興味深い取り組みが二つ存在する。一つ目はあたかもマルチスレッドアプリケーションのように動作させる方法で、もう一つは並列プログラミングのパラダイムをJavascriptに持ち込む方法である。
Javascript 1.7では、yieldが実装されている。yieldを使用すれば関数の実行を任意の場所で実行/停止させることができるので、マルチスレッドアプリケーションのように振る舞う事が出来る。ただし、Javascript 1.7を実装しているのは、Firefox 2.x以上限定である。
余談だが、yieldを使えば、ジェネレータを作成し、setTimeoutで指定秒後に実行を再開する事ができるので、sleep関数を簡単に実装できる。Thread.jsを使った例は次の通り。
function spawn(generator)
{
return new Thread(generator).start();
}
function sleep(msec)
{
setTimeout((yield CONTINUATION), msec);
yield SUSPEND;
}
spawn(function() {
console.log('start');
yield sleep(3000);
console.log('passed 3 sec.');
});
複数のBackground Processを多数のWorkerと考え、並列プログラミングのパラダイムを持ち込む動きもある。Google GearsのWorkerPool Moduleは、並列プログラミングのパラダイムをブラウザ上に導入している。しかし、Google GearsのWorker Moduleは、計算途中の状態やDOMにアクセスできない。
※ Mac OS10.4.11乗のFirefox 2.0.0.11で、workerPoolにonmessageプロパティにイベントハンドラを登録するとブラウザが必ずクラッシュする。まだ、不安定。
Client Side Storage
DB APIを提供するものと値のset / getのみ提供するシンプルなStorageの二つの取り組みがある。
- WebKit Does HTML5 Client-side Database Storage
- Google Gears Database Module API
- IEとFirefox2.0以上で動作するClient Side Storage
結論
WHATWGの興味深い新機能がブラウザに搭載されるまでには、まだしばらく時間がかかるし、ベンダー毎に取り組みも異なる。クロスドメイン非同期メッセージング, マルチスレッド(or Worker-Poolモデル), リモートイベントの処理は、Cometを利用すれば解決可能な問題である。今年は、Cometの年。Erlang OTPのプログラミングモデルや、並列プログラミングモデルをJavascriptに取り組む試みが進み、Remote Eventの操作も合成イベント(IEとの互換性を考え、dataavailable)で扱えるようなライブラリが登場するかもしれない。