WebブラウザにおけるJavaScriptは、基本的に単一スレッドでタスクを処理します。これはメインスレッドまたはイベントループと呼ばれます。しかし、Web Worker APIを使うことで、並列処理が可能になります。
メインスレッド (イベントループ)
JavaScriptのメインスレッドは、イベントループと呼ばれるメカニズムで動作します。以下の例を見てみましょう。
console.log('Start script...');
setTimeout(() => {
console.log('Timer fired');
}, 2000);
console.log('End script...');
出力結果:
Start script...
End script...
(2秒後)
Timer fired
スクリプトの実行が開始されると、コンソールに’Start script…’が出力されます。次に setTimeout関数が呼び出されますが、この関数はタイマーをスケジューリングするだけで、2秒後のコールバック関数の実行は保留されます。
その後、コンソールに’End script…’が出力され、メインスレッドのタスクが完了します。2秒後になると、保留されていたコールバック関数が実行され、’Timer fired’が出力されます。
このように、JavaScriptエンジンは単一のメインスレッドで処理を実行しますが、一定の非同期処理はイベントループに登録され、メインスレッドが空いた際に実行されます。
Web Worker
Web Workerを使うと、メインスレッドとは別の並列ワーカースレッドでタスクを実行できます。メインスレッドとWorkerスレッド間ではメッセージングによる通信を行います。
// main.js
const worker = new Worker('worker.js');
worker.onmessage = function(e) {
console.log('Main received:', e.data);
}
worker.postMessage('Hello Worker!');
console.log('Main script continuing...');
// worker.js
self.onmessage = function(e) {
console.log('Worker received:', e.data);
// 重い計算処理
let counter = 0;
for (let i = 0; i < 1000000000; i++) {
counter += i;
}
self.postMessage(counter);
}
この例では、メインスレッドからWeb Workerを作成し、メッセージを送信しています。Web Workerはメッセージを受信すると、重い計算処理を実行した後、結果をメインスレッドに返します。
メインスレッドはWeb Workerのメッセージ応答を待つことなく、’Main script continuing…’を出力し、次の処理に進みます。
Web Workerの利点は、メインスレッドをブロックすることなく、CPU負荷の高い処理を実行できることです。一方、Web Workerにはいくつかの制限があり、DOM APIにアクセスできない、ファイルシステムにアクセスできない、新しいWorkerを作成できないなどの点に注意が必要です。
近年では、Web Worker以外にも並列処理を実現する手段がいくつか登場しています。ServiceWorker、WebWorker、WebAssembly、WebGPUなどがあり、用途に応じて使い分ける必要があります。
Webブラウザ上でマルチスレッド処理を適切に利用することで、リッチでインタラクティブなWebアプリケーションを実現できます。