-
Notifications
You must be signed in to change notification settings - Fork 0
Examples
このエントリでは Thread.js のユースケースについて、例を交えながら説明していきます。
メインスレッドからワーカースレッドにメッセージ "HELLO" を渡し、ワーカースレッドで "HELLO WORLD" に加工したものを送り返すシンプルな例です。
以下は、メインスレッドのコードです。
ワーカースレッドにメッセージを送り、結果を表示します。
<script src="./lib/WebModule.js"></script>
<script src="./lib/Thread.js"></script>
<script>
var thread = new WebModule.Thread("worker.js");
thread.post(["HELLO"], null, function(args) { // ワーカースレッドに "HELLO" を送る
console.log(args[0]); // -> "HELLO WORLD";
});
</script>Thread#post の args には 数値、文字列 や Object, Array といった基本的な型の他に、 このエントリに書かれている 型を使用できます。
こちらは、ワーカースレッドのコードです。
メッセージを受けて加工し、メインスレッドに送り返します。
/// worker.js
importScripts("./lib/WebModule.js");
importScripts("./lib/ThreadProxy.js");
var proxy = new WebModule.ThreadProxy(function(args, event) {
// "HELLO" を受け取り "HELLO WORLD" に加工してポストバックします
event.postback(args[0] + " WORLD");
});この例では、メインスレッド上の TypedArray( Uint8Array ) の配列をワーカースレッドに譲渡しています。
Transferable Object の機能を使うために、Thread#post の第2引数に [ArrayBuffer] を指定しています。
var thread = new WebModule.Thread("worker.js");
var u8 = new Uint8Array(1024);
thread.post([u8.buffer], [u8.buffer]);/// worker.js
var proxy = new WebModule.ThreadProxy(function(args, event) {
var u8 = new Uint8Array(args[0]); // ArrayBuffer が渡ってくるので Uint8Array に戻します
//
});以下の例は、上記の MainThread to WorkerThread とは反対に、ワーカースレッドのメモリをメインスレッドに譲渡する例です。
ワーカースレッドにURL( http://example.com/a.png )を渡し、 ワーカースレッド上で読み込みとデコードを行い、 デコードした結果をメインスレッドに返しています。
var thread = new WebModule.Thread("worker.js", function(args) {
});
thread.post(["http://example.com/a.png"], null, function(args) {
var u8 = new Uint8Array(args[0]); // ArrayBuffer が渡ってくるので Uint8Array に戻します
//
});/// worker.js
var proxy = new WebModule.ThreadProxy(function(args, event) {
var url = args[0];
var xhr = new XMLHttpRequest();
xhr.responseType = "arraybuffer";
xhr.onload = function() {
loaded(xhr.response, url);
};
xhr.open("GET", url);
xhr.send();
function loaded(arrayBuffer, url) {
var png = WebModule.PNG.decode(arrayBuffer);
event.postback([png.buffer], [png.buffer]);
}
});Thread.js では、ワーカースレッドをメインスレッド側から終了させる事が可能です。
また、ワーカースレッドの応答が無くなった場合に備えて、強制終了させる仕組みも備えています。
以下は、ワーカースレッドをメインスレッド側からクローズする例です。
new Thread(, postMessageHandler, closeMessageHandler) のように、インスタンス作成時に closeMessageHandler を用意することで、 メインスレッド側ではワーカースレッドの終了状態(exitCode)を取得し、 ワーカースレッド側ではメインスレッドからの終了要求へ応答(YES, NO)を返すことが可能になります。
var thread = new WebModule.Thread("worker.js", function(args) {
//
}, function closeMessageHandler(exitCode) {
switch (exitCode) {
case Thread.EXIT_OK: // 正常終了しました
case Thread.EXIT_ERROR: // ワーカースレッドでエラーが発生したため終了しました
case Thread.EXIT_FORCE: // ワーカースレッドを強制終了しました
case Thread.EXIT_TIMEOUT: // ワーカースレッドの終了処理が応答を返さなかったため強制終了しました
}
});
thread.close();こちらはワーカースレッド側のコードです。closeRequestHandler の中で、メインスレッドからの要求に yes() or no() で応答できます。
/// worker.js
var proxy = new WebModule.ThreadProxy(function postMessageHandler(args, event) {
//
}, function closeRequestHandler(yes, no) {
if (1) {
yes(); // 必要な終了処理を行い、安全に終了できる場合は yes を実行します。
} else {
no(); // 終了要求を拒否する場合は no を実行します。
}
});以下は、ワーカースレッドが自分自身を終了させる例です。
var thread = new WebModule.Thread("worker.js", null, function(exitCode) {
switch (exitCode) {
case WebModule.Thread.EXIT_OK: // 正常終了しました
case WebModule.Thread.EXIT_ERROR: // ワーカースレッドでエラーが発生したため終了しました
case WebModule.Thread.EXIT_FORCE: // ワーカースレッドを強制終了しました
case WebModule.Thread.EXIT_TIMEOUT: // ワーカースレッドの終了処理が応答を返さなかったため強制終了しました
}
});
thread.post();ワーカースレッドで ThreadProxy#close を呼ぶことで自分自身を終了させます。
/// worker.js
var proxy = new WebModule.ThreadProxy(function(args, event) {
proxy.close();
});メインスレッドからの終了要求に対し、ワーカースレッドが適切に応答を返せない状況もあるかもしれません。
そのような状況に備えるために、Thread#close にはタイムアウト時間を設定できます。
var thread = new WebModule.Thread("worker.js", function postMessageHandler(args, event) {
}, function closeMessageHandler(exitCode) {
switch (exitCode) {
case WebModule.Thread.EXIT_OK: // 正常終了しました
case WebModule.Thread.EXIT_ERROR: // ワーカースレッドでエラーが発生したため終了しました
case WebModule.Thread.EXIT_FORCE: // ワーカースレッドを強制終了しました
case WebModule.Thread.EXIT_TIMEOUT: // ワーカースレッドの終了処理が応答を返さなかったため強制終了しました
}
});
thread.close(1000); // ワーカースレッドから適切な応答(yes or no)がない場合は、1秒後に強制終了させます。
// この場合の exitCode は EXIT_TIMEOUT になります。こちらはワーカースレッド側のコードです。handleClose の中で、メインスレッドからの要求に適切に応答していないため、 このままではタイムアウトしてしまいます。
/// worker.js
var proxy = new WebModule.ThreadProxy(function(args, event) {
}, function(yes, no) {
// 必要な終了処理を行い、安全に終了できる場合は yes() を実行します。
// yes();
// 終了要求を拒否する場合は no() を実行します。
// no();
});なおメインスレッドで、Thread#close(-1) とした場合は、即座に強制終了させます。
この場合の exitCode は EXIT_FORCE になります。
MessagePack と組み合わせて使用する例です。
var thread = new Thread("worker.js");
var packed = WebModule.MessagePack.encode({
msg: "HELLO",
date1: new Date(),
date2: null,
data: new Uint8Array(10)
});
thread.post([packed.buffer], [packed.buffer], function(args, event) {
var result = WebModule.MessagePack.decode(new Uint8Array(args[0]));
console.log(result.msg); // -> "HELLO WORLD";
console.log(result.date1);
console.log(result.date2);
console.log(result.data);
// done
});/// worker.js
importScripts("../node_modules/uupaa.messagepack.js/lib/MessagePack.js");
importScripts("../lib/ThreadProxy.js");
var proxy = new WebModule.ThreadProxy(function(args, event) {
var obj = WebModule.MessagePack.decode(new Uint8Array(args[0]));
obj.msg += " WORLD";
obj.date2 = new Date();
obj.data.set([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
var packed = WebModule.MessagePack.encode(obj);
proxy.post([packed.buffer], [packed.buffer]);
}, function(yes, no) {
yes();
});