Pot.js と PotLite.js で利用可能。
与えられた script と共に Worker スレッドを生成し、Pot.Workeroid の新しいインスタンスを返します。
Pot.Workeroid の解説については Pot.Workeroid を参照ください。
引数 script には、子 Worker の ファイル名、または function オブジェクト、評価される文字列などを指定します。
コンストラクタの生成と同時に、script が Worker として評価され、実行されます。
実行は常に非同期で行われ、ネイティブ Worker が利用可能な場合 別プロセスで実行されます。
script がファイル名の場合、従来の Worker と同じように実行されます。
この場合、onmessage = function(event) {...}
と イベントの設定が必要です。
script が function オブジェクトの場合、その関数を onmessage のイベントとして設定し、評価します。
script が function オブジェクトであり、コード内に onmessage = function(event) {...}
の設定がされていた場合
イベントとして設定はされずに評価されます。
また、子 Worker から Pot オブジェクトが利用できます。
Pot.js が実行中でであれば Pot.js が、PotLite.js が実行中の場合は PotLite.js がデフォルトで利用可能です。
したがって、Pot.Deferred.forEach などを利用し CPU を抑えたループが利用できます。
子 Worker 内の Pot オブジェクトは、親スレッドでの Pot オブジェクトとは別のオブジェクトです。
var worker = new Pot.Workeroid(function(data) {
//
// このスコープの中が 子 Worker スレッド
//
var add = 1;
postMessage(data + add);
});
// メッセージを受信した時
worker.onmessage = function(data) {
alert(data);
};
// 1 を 子 Worker に送信 => 2 が alert される
worker.postMessage(1);
ファイル名を渡すことに慣れている場合、分かり難いかもしれませんが
コンストラクタに渡した function が、子 Worker の onmessage に設定されます。
つまり、渡した function は別スレッドで動きます。(エミュレート時以外)。
引数の data は、event.data にあたるものです。
function オブジェクトを直接指定した場合、event.data がそのまま 第一引数に返ります。
event オブジェクトを取得したい場合は、第二引数から取得できます。
Pot.globalize() が適応されている場合、new Pot.Workeroid() が new Workeroid() で実行できます。
新しい Pot.Workeroid インスタンスが返ります。
script に function オブジェクトを渡した場合の例:
var worker = new Pot.Workeroid(function(data) {
//
// このスコープの中が 子 Worker スレッド
//
var add = 1;
postMessage(data + add);
// self.postMessage(...) でも可
});
// メッセージを受信した時 (addEventListener でも設定可)
worker.addEventListener('message', function(data, event) {
alert(data);
}, false);
// 1 を 子 Worker に送信 => 2 が alert される
worker.postMessage(1);
script に ファイル名で指定した場合の例:
worker.example.parent.js :
var worker = new Pot.Workeroid('worker.example.child.js'); // メッセージを受信した時 (addEventListener でも設定可) worker.onmessage = function(data, event) { alert(data); }; // エラー時の設定 (任意) worker.onerror = function(err) { alert(err); }; // 1 を 子 Worker に送信 => 2 が alert される worker.postMessage(1);
worker.example.child.js :
// 子 Worker 内 var add = 1; onmessage = function(event) { postMessage(event.data + add); };
script に function で指定し、その関数内で onmessage の設定を持つ場合:
この場合は ファイル名指定と同じく onmessage 関数に event オブジェクトが直接渡される。
var worker = new Pot.Workeroid(function() {
//
// このスコープの中が 子 Worker スレッド
//
var add = 1;
onmessage = function(event) {
postMessage(event.data + add);
};
});
// メッセージを受信した時
worker.onmessage = function(data, event) {
alert(data);
};
// 1 を 子 Worker に送信 => 2 が alert される
worker.postMessage(1);
このように ファイル名指定と同じく onmessage の指定と共に実行できますが、
Pot.Workeroid では、onmessage の設定のない function 指定を推奨します。
これは、onmessage の外側のスコープの扱いがブラウザ間で異なる場合があることと、
引数が event なのか data なのか混乱することを避けるためです。
子 Worker からデフォルトで利用できる Pot オブジェクトを利用すると、
CPU 負荷をかけずに実行することができます。
var worker = new Pot.Workeroid(function(data) {
//
// このスコープの中が 子 Worker スレッド
//
var n = 1;
search: while (true) {
n += 1;
for (var i = 2; i <= Math.sqrt(n); i += 1) {
if (n % i == 0) {
continue search;
}
}
// 素数をポスト
postMessage(n);
}
});
// メッセージを受信した時
worker.onmessage = function(data, event) {
Pot.debug(data);
};
// Worker を開始
worker.postMessage();
この例では、素数をひたすら 親スレッドへポストし続けます。
その間、処理はバックグラウンドで行われますが CPU の配慮がありません。
そこで、Pot.js のイテレータを利用します。
var worker = new Pot.Workeroid(function(data) {
//
// このスコープの中が 子 Worker スレッド
//
var n = 1;
Pot.Deferred.forEver(function() {
n += 1;
for (var i = 2; i <= Math.sqrt(n); i += 1) {
if (n % i == 0) {
return;
}
}
// 素数をポスト
postMessage(n);
});
});
// メッセージを受信した時
worker.onmessage = function(data, event) {
Pot.debug(data);
};
// Worker を開始
worker.postMessage();
Pot.Deferred.forEver は、StopIteration が throw されるまでイテレートします。
この変化により、CPU 使用率は減少し安定したスレッドに保てます。
必要に応じて、Pot.Deferred.forEver.slow(...)
などの速度調整が可能です。
速度の調整については Deferred 速度の指定 を参照ください。
Pot.Deferred チェイン の中で Pot.Workeroid インスタンスを返すと、
子 Worker が postMessage するまで待機します。
var worker = new Pot.Workeroid(function(data) {
//
// このスコープの中が 子 Worker スレッド
//
// タイマーで順序を狂わせるように返す
switch (data) {
case 'foo':
setTimeout(function() {
postMessage('Foooooooooo!');
}, 3000);
break;
case 'bar':
Pot.callLater(2, function() {
postMessage('Baaaaaaaaaaaa!!');
});
break;
case 'baz':
setTimeout(function() {
postMessage('Baaaaaaaaaz!!!');
}, 20);
break;
}
});
worker.onmessage = function(data) {
Pot.debug(data);
};
Pot.Deferred.begin(function() {
worker.postMessage('foo');
// worker を返すことで
// 子 Worker が postMessage するまで待機
return worker;
}).then(function() {
worker.postMessage('bar');
return worker;
}).then(function() {
worker.postMessage('baz');
return worker;
});
//
// 結果:
// 'Foooooooooo!'
// 'Baaaaaaaaaaaa!!'
// 'Baaaaaaaaaz!!!'
// の順でコンソールに出力される
//