| 目次 |
|---|
|
・Web Workersとは ・重いスクリプト ・Web Workersの使い方 ・スクリプトのインポート ・Web Workersの活用シーン |
Web Workersは、Javascriptの処理をバックグランドで実行するメカニズムを提供します。
ブラウザに限らず、多くのアプリケーションは「プロセス」と言う単位で動きます。
WEBブラウザの多くも、タブやウィンドウで分かれていても、ほとんどが「一つのプロセス」の中で実行されます。
そのため、一つのタブやウィンドウの処理が遅くなったり、クラッシュするとそのアプリケーション全体に影響が及びます。
そのため、「マルチプロセス」に対応したブラウザも存在します。(Google Chromeなど)
「マルチプロセス」にすることで、一つの処理が重くて遅くなったり、クラッシュしても他のタブやウィンドウには影響しないようになります。
なお、近年のOSのほとんどは「マルチプロセス」に対応しているため、そのアプリケーションではクラッシュしても他のアプリケーションには影響しないようになっています。
「マルチプロセス」になれば、同じブラウザ内でタブやウィンドウが違えば他の処理に影響されないのですが、同じタブやウィンドウ内 つまり一つのページを処理している間は、その処理が終わるのを待つ必要があります。
例えば、<head>内で呼び出される外部スクリプトファイルが大変大きなものが定義されているページを読み込む場合、外部スクリプトファイルの処理が完了するまで、ページの表示だけでなく、ブラウザの操作自体ができません。
これを解決する方法として「マルチスレッド」というものがあります。
「マルチスレッド」とは、1つのプロセス(アプリケーション)内で、同時並行に独立して処理を行うメカニズムです。
「マルチプロセス」は、それぞれのプロセスが完全に独立しているのに対し、「マルチスレッド」はそれぞれのスレッドがメモリ空間を共有します。
そのため「マルチプロセス」に比べメモリ消費を抑えられると共に、同じメモリ空間のデータを共有することができます。
しかし「マルチスレッド」はその制御、特にデータの競合や排他処理をうまく行わないとプロセス自体が動かなくなってしまいます。
このように「マルチスレッド」を行うプログラムは大変複雑なものとなります。
本題のWeb Workersは、「マルチスレッド」に似ています。
しかしWeb Workersは、メモリ空間のデータ - ブラウザ上のページ内容(windowオブジェクトやdocumentオブジェクトなど) を共有することはできません。
データの共有はできないのですが、その代わりにデータの競合や排他処理を行う必要がありません。
このようにスレッドに似たWeb Workersで処理する単位を「ワーカー」と呼びます。
このページでは、この「ワーカー」の利用方法について紹介致します。
Web Workersは、2011年8月現在以下のブラウザで対応しています。
FireFox 3.5~、Safari 4~、Opera 10.6~、Google Chrome 3~
(IEでは10~の予定)
まずはWeb Workersを使わなかった場合の処理と用意してみます。
次のサンプルスクリプトは、単純にfor文で繰り返し、累積値を算出します。
リスト1. 重い処理例
//通常の処理...ハングアップします。
function myStart01(me){
var op = document.getElementById('myOutput01');
op.innerHTML = "";
me.innerHTML = "処理中";
var s = 0;
var n = 3000000000;
for(var i=0;i<n;i++){
s = mySigma(s, i);
}
op.innerHTML = s;
me.innerHTML = "実行";
}
//累積結果を得る
function mySigma(s, i){
return s+i;
}
実装例
実行内容:
※注意! この実装例は非常に時間が掛かる処理で、場合によりWEBブラウザは応答できなくなります。
なるべく実行しないでください。
次のサンプルスクリプトはWeb Workersを使った例です。
前項同様、単純にfor文で繰り返し、累積値を算出します。
処理内容はほぼ同じですが、Web Workersを使うことで、表示しているこのページと別途に実行されます。
そのため、処理中でもメニュー操作などを行うことができます。
Web Workersは、呼び出し側(親側)とワーカー側のファイルを分けて用意します。
親側とワーカー側をつなぐのは「postMessage」メソッドです。
この「postMessage」メソッドで親とワーカー間でデータのやりとりをします。
Web Workersのイベントは「onmessage」と「onerror」です。
リスト2. Web Workersの例(親側)
//Web Workersを利用
function myStart02(me){
var op = document.getElementById('myOutput02');
op.innerHTML = '';
// Workersオブジェクト
var worker = new Worker('wrkr01.js');
// messageイベントのハンドラをセット
worker.onmessage = function(evt){
var res = evt.data;
// ワーカーから返ってきた情報を表示
op.innerHTML = res;
me.onclick = function(){
myStart02(me);
}
me.innerHTML = "実行";
}
// errorイベントのハンドラをセット
worker.onerror = function(evt){
var msg = "";
msg += evt.message + "\n";
msg += "Line : " + evt.lineno;
alert(msg);
}
// ワーカーに処理開始のメッセージを送る
worker.postMessage('start');
// ボタンの処理を定義
me.innerHTML = "処理中(キャンセル)";
me.onclick = function(){
worker.terminate();
op.innerHTML = 'キャンセルされました';
me.onclick = function(){
myStart02(me);
}
me.innerHTML = "実行";
}
}
リスト3. Web Workersの例(ワーカー側)
// wrkr01.js の中身
//親からメッセージを送られてきたとき
self.onmessage = function(event){
//親から送られてきた命令
var cmd = event.data;
//命令の実行
switch(cmd){
case 'start':
myStart();
break;
}
}
//繰り返しの実行
function myStart(){
var s = 0;
var n = 3000000000;
try{
// n回加算
for(var i=0;i<n;i++){
s = mySigma(s, i);
}
self.postMessage(s);
}
catch(e){
// 例外処理
self.postMessage(' Error:' + e.message);
}
}
//累積結果を得る
function mySigma(s, i){
return s+i;
}
実装例
実行内容:
「ワーカー定義スクリプトファイル」内で、jQueryなど外部スクリプトライブラリを使いたい場合、
<script src="外部スクリプトライブラリ"></script>
というわけには行きません。
そこで、「impoerScripts」メソッドを用いて外部スクリプトライブラリを呼び出します。
Web Workersを使う場面はいろいろとあります。
以下は、その一例です。
Web Workersを用いることで、利用者にストレスを感じさせず、複雑な処理を行うことが出来るようになります。