HTML5 Web Workers 入門
Web Workers概要
JavaScriptのコードをバックグラウンドで処理させる事ができる。別々のスレッドでJavaScriptを実行できるのでマルチコアのCPUを有効活用するアプリケーションを作れる。
対応ブラウザ(2010/9現在)
バックグラウンド?
ブラウザは単一のスレッド(= UI スレッド)で実行されているので、JSによる演算とDOMの操作が同じスレッド上で実行されている。
そのため、処理に時間がかかってしまうとDOMの操作(= UIの変更)にも影響が出る。最悪の場合にはプログラムの停止が求められる。
UIスレッド
UIスレッドは単純なキューイングシステムで、タスクはアイドル状態になるまでキューに並ぶ仕組み。UIスレッドのタスクにはUIの変更も、コードの実行も含まれる。
注意しないといけないのは、入力によっては新たにキューに加わるタスクを生成する可能性があるということ。
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>UI thread test</title> </head> <body> <button id="trig">click</button> <script type="text/javascript"> document.getElementById('trig').addEventListener('click', function() { var div = document.createElement('div'); div.innerHTML = "Hi!"; document.body.appendChild(div); }, false); </script> </body> </html>
ボタンがクリックされると
- ボタンがクリックされた時の見た目の変化を起こすタスク
- 定義したイベントリスナの実行
という2つのタスクがキューに追加されて、この順番で処理が行われる。
イベントリスナでは、divを生成してbodyに追加する処理を行っているので、コードの実行中にこの処理が新たにタスクとしてキューに追加される。
タスクの実行中にはUIの更新が即実行されない他、更新するための新しいタスクが新たにキューに並ぶ可能性があるが、実際のところ、ほとんどのブラウザではユーザの操作を邪魔しない様に、JavaScriptのコード実行中はコードを終了させる事を優先してUIスレッドにタスクを追加しない様になっている。
とりあえず使ってみる
Web Workerオブジェクトが生成されると、postMessage APIを使ってメッセージのやり取りができる様になる。
workers.html(main.js) <->worker.jsでメッセージをやり取りする。
workers.html
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8" /> <title>Web Workers test</title> <style> p#response { color: red; } </style> </head> <body> <h1>Web Workers Sample</h1> <p id="support"></p> <div> <a id="start" href="#">start</a> <a id="stop" href="#">stop</a> </div> <p id="response"></p> <script type="text/javascript" src="main.js"></script> </body> </html>
main.js
var main = { init: function() { if(this.chkCompatible()) { this.initWorker(); } }, // ブラウザ対応のチェック chkCompatible: function() { if(typeof(Worker !== "undefined")) { document.getElementById("support") .innerHTML = "This browser supports Web Workers!"; return true; } return false; }, initWorker: function() { // workerとして実行したいJSファイルを相対/絶対パスで指定する // 同一出身のファイルのみ可能 var worker = new Worker('worker.js'); document.getElementById('start').addEventListener('click', function() { // workerへメッセージ送信 worker.postMessage('message to worker'); }, true); document.getElementById('stop').addEventListener('click', function() { // workerの停止 // worker自身で停止する事ができないので呼び出しもとで停止させる worker.terminate(); console.log('terminate worker:', worker); }, true); //workerからのメッセージに応答する worker.addEventListener('message', this.messageHandler, true); worker.addEventListener('error', this.errorHandler, true); }, messageHandler: function(e) { document.getElementById('response').innerHTML = e.data; }, errorHandler: function(e) { console.log(e.message, e); } } window.onload = function() { main.init(); };
worker.js
function messageHandler(e) { postMessage('worker.js got: ' + e.data); } addEventListener('message', messageHandler, true);
この辺のサンプルの方が役に立ちそう。
http://blog.mozbox.org/post/2009/04/10/Web-Workers-in-action