WebWorker?とは †
- HTML/Javascript は、原則的に一つのスレッドで動いていた
- setTimeout(func, 999) は、func の実行を 999 ms 後に実行するだけで、並列に動作するわけではない
- Promise なんかも並列に動作するわけではなく、ブラウザの描画スレッドの中でのイベント待ちをしている
- WebWorker?を使うと、Javascriptでもマルチスレッドアプリを作ることができる
- 使い方 → サンプルアプリを参照
- ★留意事項
- Workerスレッド側で、DOM にアクセスすることができない
- jQuery は使えないことに注意 ! $.get() とかは、内部的に DOM を使っている。Workerスレッド側で Ajax をしたいときには XMLHttpRequest? を生で使う必要がある
サンプルアプリ †
- サンプルアプリについて
- メインスレッドで時計が動いている (500ms ごとに表示を更新している)
- ボタンを押して重い処理を動かして、CPUメータが 1Core 100% 使われていることを確認してください
- Workerを呼び出して重い処理をしても、Workerスレッドの負荷が100%になるだけなので、メインスレッドで動いている時計は止まらない
- メインスレッド内で重い処理をすると、メインスレッドの負荷が100%になるので、メインスレッドで動いている時計が止まってしまう
- index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<span id="clock"></span> <br/>
<table border=0>
<tr><td>Worker を起動</td><td><button id="btn1">Run</button></td></tr>
<tr><td>通常の関数呼出</td><td><button id="btn2">Run</button></td></tr>
</table>
<script
src="https://code.jquery.com/jquery-3.3.1.slim.min.js"
integrity="sha256-3edrmyuQ0w65f8gfBsqowzjJe2iM6n0nKciPUp8y+7E="
crossorigin="anonymous"></script>
<script>
// 時計 (メインスレッド)
function clock() {
$('#clock').text(new Date());
setTimeout(clock, 500);
}
clock();
// 別スレッドで重い処理を動かす
var worker = new Worker('js/worker.js');
$('#btn1').on('click', function(){
var $btn = $(this);
// 別スレッドの処理起動
$btn.text('Processing');
$btn.prop('disabled', true);
worker.postMessage('start');
});
// 別スレッドの処理終了
worker.addEventListener('message', function(e) {
console.log(e.data);
var $btn = $('#btn1');
$btn.text('Run');
$btn.prop('disabled', false);
}, false);
// メインスレッドで重い処理を動かす
$('#btn2').on('click', function(){
var $btn = $(this);
// 別スレッドの処理起動
$btn.text('Processing');
$btn.prop('disabled', true);
// setTimeout をかまさないと、ボタンのラベルが "Processing"
// になる前に main thread の負荷が 100% になる
setTimeout(function(){
console.log('start');
// 何かの重い処理
for(cnt1=0; cnt1<50; cnt1++) {
for(cnt2=0; cnt2<10000; cnt2++) {
for(cnt3=0; cnt3<10000; cnt3++) {
}
}
}
console.log('end');
// 終了後の処理
$btn.text('Run');
$btn.prop('disabled', false);
},100);
});
</script>
</body>
</html>
- js/worker.js
self.addEventListener('message', function(e) {
// receive objeect from main thread
console.log(e.data);
for(cnt1=0; cnt1<50; cnt1++) {
for(cnt2=0; cnt2<10000; cnt2++) {
for(cnt3=0; cnt3<10000; cnt3++) {
}
}
}
// send object to main thread
self.postMessage('loop end');
}, false);
HTML