検索
連載

並列処理を実現!Web Workersを使いこなそう連載:人気順に説明する初めてのHTML5開発(2/2 ページ)

JavaScriptコードの重い処理を、バックグラウンドで動作させてレスポンスを改善したい。それなら、Web Workersを使おう。

PC用表示 関連情報
Share
Tweet
LINE
Hatena
前のページへ |       

■ワーカーと同期APIの組み合わせ例

 それでは、実際にワーカーを活用したサンプルを紹介する。

 前回予告したように、今回は同期APIを利用したファイル内容の取得について紹介する。利用するAPIは、Web Workerと、Drag And Drop API、File APIである。

 内容は、前回の記事のサンプルを、ワーカーを利用して実装しただけだ。ドラッグ&ドロップでファイルをドロップした場合に、バックグラウンドのワーカーでテキストファイルか画像ファイルを(同期処理用の)FileReaderSyncオブジェクトで読み取り、その内容をUIスレッドで表示するサンプルを作成する。実行結果は図4〜6になる。こちらから実際に試せる。


図4 サンプル・アプリケーションを実行した直後の表示例


図5 画像ファイルをドロップしたときの例


図6 テキスト・ファイルをドロップしたときの例

 まずはUIスレッド側のコードだ。

<div id="drop"
  style="width:700px; height:150px; padding:10px; border:3px solid"
  ondragover="onDragOver(event)">
  ここにドロップしたファイルの内容を表示します。</div>
<br />

<div id="disp" ></div>
<script type="text/javascript">
if (window.Worker) {
  // Web Workersに関する処理を記述
  var worker = new Worker("fileworkers.js");

  if (window.File) {
    // File APIに関する処理を記述
    document.getElementById("drop").addEventListener("drop", onDrop, false);
  } else {
    window.alert("本ブラウザではFile APIが使えません");
  }

} else {
  window.alert("このブラウザではWeb Workersは利用できません");
}

// (1)Drop領域にドロップした際のファイルの読み取り処理
function onDrop(event) {
  var files = event.dataTransfer.files;
  document.getElementById("disp").innerHTML = "";

  for (var i = 0; i < files.length; i++) {
    var f = files[i];
    worker.postMessage({ "file": f, "type": f.type });
  }

  // ブラウザ上でファイルを展開する挙動を抑止
  event.preventDefault();
}

function onDragOver(event){
  // ブラウザ上でファイルを展開する挙動を抑止
  event.preventDefault();
}

// (2)ワーカーからのメッセージ取得時の処理
worker.onmessage = function (event) {
  var ret = event.data;

  if (ret.type.match('image.*')) {
    var li = document.createElement('li');
    var img = document.createElement('img');
    img.src = ret.val;
    li.appendChild(img);
    li.innerHTML += "<br />";
    document.getElementById("disp").appendChild(li);

  } else if (ret.type.match('text.*')) {
    document.getElementById("disp").innerHTML = ret.val;
  }
}
</script>

File APIとワーカーを組み合わせた例〜UIスレッド側〜(WebWorkers.htm

(1)Drop領域にドロップした際のファイルの読み取り処理

 Drag and Drop APIを使用し、ファイルがドロップされた際の処理を記述している。今回はワーカー側でファイル読み取り処理を実施するので、ドロップされたファイルを1つずつワーカー側に渡している。その際に使用されるpostMessageメソッドの引数で、「ファイル(file)」と「ファイルを読み込むためのファイルのMIMEタイプ(type)」の2つを渡している。

(2)ワーカーからのメッセージ取得時の処理

 ワーカーからメッセージを取得したときの処理をonmessageメソッドに記載している。今回は、ワーカーから取得したメッセージのデータは、「MIMEタイプ(type)」と「読み込んだファイル・データ(val)」となる。

 MIMEタイプを利用して画像ファイルかテキスト・ファイルかを判定し、それぞれ向けに後続の処理を分けている。テキスト・ファイルの場合は読み込んだテキストをそのまま表示できるが、画像ファイルの場合は<img>要素のsrc属性に読み込んだ画像データ(=データURI*1形式の文字列)をセットする必要があるためだ。

*1 <img>要素のsrc属性や、CSSのbackgroundプロパティなどのコンテキストに、画像などのデータを埋め込む手段。例えば「<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAIAAAFSDNYfAAAAaklEQVR42u3XQQrAIAwAQeP%2F%2F6wf8CJBJTK9lnQ7FpHGaOurt1I34nfH9pMMZAZ8BwMGEvvh%2BBsJCAgICLwIOA8EBAQEBAQEBAQEBK79H5RfIQAAAAAAAAAAAAAAAAAAAAAAAAAAAID%2FABMSqAfj%2FsLmvAAAAABJRU5ErkJggg%3D%3D">」のような形で埋め込める。詳しくは「MSDN:data Protocol」を参照してほしい。


 続いて、ワーカー側で使用されるJavaScriptファイルのコードだ。

onmessage = function (event) {
  // (1)同期APIの用意
  var reader = new FileReaderSync();
  var datafiles = event.data;
  var val = "";

  // (2)ファイルの種類を判定したうえでの処理
  if (datafiles.type.match('image.*')) {
    val = reader.readAsDataURL(datafiles.file);
  }

  if (datafiles.type.match('text.*')) {
    val = reader.readAsText(datafiles.file, 'shift-jis');
  }

  // (3)UIスレッドに処理結果を送る
  postMessage({ "type": datafiles.type, "val": val });
}

File APIとワーカーを組み合わせた例〜ワーカー側〜(fileworkers.js

(1)同期APIの用意

 前回紹介したFile APIのサンプルでは非同期APIであるFileReaderインターフェイスを使用して作成したが、今回はワーカー上でのみ使用可能なFileReaderSyncインターフェイスを使用する。FileReaderSyncインターフェイスでは、FileReaderインターフェイス同様にreadAsBinaryStringメソッド、readAsTextメソッド、readAsDataURLメソッドを使用する。非同期APIであるFileReaderの場合は、イベント経由でしか値を取得できなかったが、FileReaderSyncの場合は、メソッドの戻り値として値を取得できるのが特徴だ。

 上記では、ワーカーが用意された段階で、FileReaderSyncインターフェイスのオブジェクトを生成している。

(2)ファイルの種類を判定したうえでの処理

 UIスレッドから取得したメッセージ・データからMIMEタイプを確認し、画像ファイルの場合は、readAsDataURLメソッドで画像ファイルを読み込んだ結果を、変数valに設定している。テキスト・ファイルの場合は、readAsTextメソッドでテキスト・ファイルを読み込んだ結果を変数valに設定する。

(3)UIスレッドに処理結果を送る

 UIスレッドに「読み込み結果(val)」と「MIMEタイプ(type)」を送っている。

 実行結果は先ほどの図4〜6のとおりである。ケース・バイ・ケースだが、例えば大量のファイルを扱う場合や、サイズの大きいファイルを複数扱う場合などには、ワーカーを使うということも含めて検討してみるとよいだろう。

■まとめ

 今回は、JavaScriptをバックグラウンドで実行するWeb Workersについて紹介した。実装も進んでおり、処理を分離させつつ、ローカルのリソースも効果的に使えるWeb WorkersはHTML5アプリケーションのバックボーンとして活躍するだろう。

 ぜひ基礎を押さえて、効果的なHTML5アプリケーション開発に役立ててもらえれば幸いだ。

 最終回となる次回は、ブラウザ上で動作するキー・バリュー型のデータベース「Indexed DataBase」を紹介する。お楽しみに。

「連載:人気順に説明する初めてのHTML5開発」のインデックス

連載:人気順に説明する初めてのHTML5開発

Copyright© Digital Advantage Corp. All Rights Reserved.

前のページへ |       
ページトップに戻る