クロスドキュメントメッセージングやWebSocketを使ってみる

2012年5月15日(火)
飯島 聡(著)山田 祥寛(監修)

messageイベントオブジェクトのプロパティは、以下の通りです。

表2:messageイベントオブジェクトの主なプロパティ

プロパティ 概要
data 受信データ
origin 送信元のオリジン
source 送信元ページ

重い処理によるブラウザの応答停止を回避する - Web Workers

Web Workersは時間のかかる処理をブラウザのUIとは別の部分で動作させる仕組みです。時間のかかる処理をUIの部分と同じスレッドで実行すると、その処理の最中はブラウザが応答しなくなってしまいます。Web Workersはこれを解消する機能です。Web Workersはリモートサイト間のコミュニケーションではありませんが、他のコミュニケーション系APIと同様にpostMessageとmessageイベントを使用するため、ここで紹介しています。

 図3:Web Workers(クリックで拡大)

時間のかかる計算を実行するサンプル

以下のサンプルは、上部のテキストフィールドに、整数を入力して、計算ボタンを押すと、下のフィールドにその整数の素因数分解がJavaScriptの数式の形式で出力されるというものです。Worker不使用のサンプルとWorker使用のサンプルを作成して比較しました。

 図4:Worker不使用のサンプルでは応答が止まってしまう(クリックで拡大)

Workerを使用しないサンプルではブラウザの応答が止まってしまい、ウィンドウにアクセスしようとすると強制終了するかを問うダイアログが表示されます。

 図5:Worker使用のサンプルでは計算中もウィンドウにアクセス出来る(クリックで拡大)

一方、Workerを使用したサンプルでは計算中も情報の表示や、ウィンドウへのアクセスができます。

Worker不使用サンプル「HTML5_4_sample3_1.html」も処理はほとんど同じなので、コードは割愛します。ダウンロードをご参照ください。以下ではWorkerを使用するサンプルのみ説明します。

[サンプル]素因数分解をWorkerで演算するサンプル(HTML5_4_sample3_2.html)

  //Workerオブジェクトを作成、バックグラウンドで動かすJavaScriptを指定	・・・(1)
  var worker = new Worker("HTML5_4_sample3.js");
  //Workerの開始
  function startWorker(){
    var t1 = document.getElementById("t1");
    //postMessageでWorkerに処理を開始させる					・・・(2)
    worker.postMessage(t1.value);
    var t2 = document.getElementById("t2");
    //処理の間、計算を待たずにGUI部分の処理もできる				・・・(3)
    t2.value = "バックグラウンドで計算中・・・";
    var button = document.getElementById("recalculation");
    button.disabled = true;
  }
  //Workerが結果を返した時の処理を登録							・・・(4)
  worker.addEventListener("message",displayResult,true);
  //Workerが結果を返した時の処理
  function displayResult(e){
    //テキストフィールドに結果データを表示						・・・(5)
    t2.value = e.data;
    var button = document.getElementById("recalculation");
    button.disabled = false;
  }
  //(HTML部分)
  <h1>Web Workersを使用するサンプル</h1>
  <h3>素因数分解</h3>
  <form name="f1" id="f1">
    整数を入れてください:<input type="text" id="t1" size="15" value="10000000000001">
    <!-- 計算ボタン -->
    <input type="button" value="Workerを使用して計算" onclick="startWorker();" >
    <br>
    計算結果:<input type="text" id="t2" placeholder="結果" size="50">
    <!-- 検算用ボタン -->
    <input type="button" id="recalculation" value="検算" onclick="alert(eval(t2.value));" ><br>
  </form>
  • (1) 実際にブラウザのバックグラウンドで処理をするワーカーをJavaScriptから起動するには、Workerオブジェクトを使用します。コンストラクタの引数には、バックグラウンドで動かしたいJavaScriptファイルを指定します。
  • (2) 処理は、postMessageメソッドで開始します。引数に入力値を設定します。
  • (3) このように、postMessageメソッドでWorkerに処理を渡した後、結果を待つ間もUIの操作が可能です。
  • (4) Workerから計算結果を受け取った場合の処理を、messageイベントハンドラに登録します。
  • (5) 結果はmessageイベントオブジェクトeのdataプロパティでアクセス出来ます。

[サンプル] Workerに処理させる計算ロジック(HTML5_4_sample3.js)

  //メッセージ受信のハンドラ								・・・(1)
  onmessage = 
    function (e){
    var product="";
    //引数の代わりにe.dataに入力データが入っている	・・・(2)
    var j = eval(e.data);
    if (j <= 1){return integer};
    var k;
    for(k=2; k <= j; k += (k>2) ? 2 : 1){
      if (j % k == 0){
        var m = 0;
        while(j>1 && j % k == 0){
          j /= k;
          m++;
        }
        if(j>=1){
          product += (product.length>0) ? "*" : "";
          product += (m>1) ? "Math.pow("+k+","+m+")" : k;
        }
      }
    }
    //returnの代わりにpostMessage()で戻り値を返す	・・・(3)
    postMessage(product);
  }
  • (1) Workerで動かすjsファイルには、UI側からのメッセージを受信した時に発生する、messageイベントのハンドラを記述します。
  • (2) 入力値は引数の代わりにmessageイベントオブジェクトeのdataプロパティから取得します。
  • (3) 計算や処理の結果を、returnの代わりにpostMessageメソッドで呼び出し元にメッセージを返信しています。

リアルタイムのコミュニケーションを実現する - WebSocket

WebSocketとは、サーバー - ブラウザ間のリアルタイム双方向通信用の規格です。WebSocketでは独自のプロトコルを用います。HTTPと違い、接続の確立が最初だけで同じ接続を使用し続ける事や、サーバー側から応答以外のメッセージの送信が可能となり、HTTPでは実現の難しかったリアルタイムコミュニケーションが可能となります。オンラインゲームの実装などに応用出来る技術です。

 図6:WebSocket(クリックで拡大)

WebSocketの実行環境

WebSocketを使用するためにはWebSocketに対応したサーバーが必要です。以下に主な対応サーバーを挙げています。

表3:WebSocketに対応した主なサーバー

名前(サイト) 概要 サーバーアプリ記述言語
Jetty (http://www.eclipse.org/jetty/ ) Javaで作成されたWebサーバー Java
jWebSocket Server (http://jwebsocket.org/) Javaで作成されたWebサーバー Java
libwebsockets (http://git.warmcat.com/cgi-bin/cgit/libwebsockets/) C言語用Websockets Serverライブラリ C
SuperWebSocket (http://superwebsocket.codeplex.com/) .NET用WebSocket Server C#,VB.NET
Apache+pywebsocket (http://code.google.com/p/pywebsocket/) WebSocket server/Apache用WebSocket機能拡張 python
node.js+Socket.IO (http://socket.io/) JavaScript用Webサーバー(node.js)とそのWebSocket機能拡張 JavaScript(WebSocket非対応ブラウザも考慮されている)

WebSocketプロトコルの仕様は、2011年12月11日のRFC 6455に至るまでの草案の時から公開されていましたが、何度も改訂されていました。その結果、ブラウザ、サーバーとも実装されているプロトコルが一貫していません。

hybi-xxとは、各草案の名称「draft-ietf-hybi-thewebsocketprotocol-xx」の略で、xxは改訂番号です。例えば、hybi-00とhybi-10には互換性はありません。主な、改訂とブラウザの実装の対応状況を以下の表にまとめました。

表4:ブラウザのWebSocketプロトコル対応状況

  IE9 Chrome18 Firefox11,12 Opera11.62 Safari5.1.5
hybi-00 × × ○(*)
hybi-10 × × ×
RFC 6455(hybi-17) × × ×
(*)設定が必要。有効にするにはアドレスバーから「opera:config#Enable%20WebSockets」と入力して、設定画面を開いてチェックボックスをオンにして保存する。

サンプルでは、hybi-10に対応したサーバーを使用するために、ChromeとFirefoxのみで確認しています。

サーバーは、nodejs.org(http://nodejs.org/)のWindows版node v0.6.15とnodeモジュールのWorlize/WebSocket-Node1.0.3で確認しました。nodeはサーバー側のコードをJavaScriptで実装出来るWebサーバーです。追加機能がモジュールの形で提供されています。WebSocket対応化モジュールはWebSocket-Nodeの他に、Socket.IO、websocket-serverなどがあります。Socket.IOが最も実装が進んでいて高機能ですが、ブラウザ側コードもSocket.IO独自のものとなってしまうために、今回はWebSocket-Nodeを使用しました。

◆◇◆◇ コラム:Windows版nodeとWebSocket-Nodeのインストールと起動の手順 ◆◇◆◇

  1. nodejs.orgのサイトからインストーラ(msiファイル)をダウンロードしてインストール
  2. Program Filesフォルダのnodejsにnode.exeやnpm.cmdがインストールされている事を確認(npmはnodeのパッケージ管理ツールです。インターネットに接続されている環境ではコマンド1つでnodeモジュールをインストール出来ます。)
  3. コマンドプロンプトを開き「npm install websocket@1.0.3」を実行(最新版は1.0.4だがエラーになるため)
  4. nodejs\node_modulesフォルダにwebsocketがインストールされている事を確認
  5. 「node app.js」(app.js:サーバーコードの記述されたJavaScriptファイル)でサーバー起動
  • HTML5のコミュニケーション機能サンプル

著者
飯島 聡(著)山田 祥寛(監修)
WINGSプロジェクト

有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティ(代表:山田祥寛)。おもな活動は、Web開発分野の書籍/雑誌/Web記事の執筆。ほかに海外記事の翻訳、講演なども幅広く手がける。2011年3月時点での登録メンバは36名で、現在もプロジェクトメンバーを募集中。執筆に興味のある方は、どしどしご応募頂きたい。著書多数。

連載バックナンバー

Think ITメルマガ会員登録受付中

Think ITでは、技術情報が詰まったメールマガジン「Think IT Weekly」の配信サービスを提供しています。メルマガ会員登録を済ませれば、メルマガだけでなく、さまざまな限定特典を入手できるようになります。

Think ITメルマガ会員のサービス内容を見る

他にもこの記事が読まれています