【JS応用|実務向け】Web Workerを使いこなす:Worker.prototype.terminateでリソースを適切に解放する

導入

フロントエンド開発において、重い計算処理やメインスレッドをブロックするようなタスクを実行する際、Web Workerは欠かせない存在です。しかし、Workerを起動しっぱなしにすると、ブラウザのメモリを圧迫し、パフォーマンス低下やメモリリークの原因となります。そこで重要になるのが、Workerのライフサイクルを管理するWorker.prototype.terminateメソッドです。この記事では、Workerを即座に強制終了させ、リソースを適切に解放する方法を解説します。

基礎知識

Web Workerは、ブラウザのメインスレッドとは別のバックグラウンドスレッドでスクリプトを実行する仕組みです。通常、Worker内の処理が完了しても、明示的に終了させない限りスレッドは維持されます。Workerを終了させる方法には、Worker内部から呼ぶ「self.close()」と、メインスレッドから制御する「worker.terminate()」の2種類があります。terminateメソッドは、Workerのタスクが進行中であっても、即座に中断させることができる強力な制御ツールです。

実装/解決策

terminateを呼び出すと、Workerは即座に停止します。この際、Worker側で実行中の処理は中断され、イベントループも停止します。注意すべき点は、terminateによる終了は「強制終了」であるため、Worker側でクリーンアップ処理(メモリの解放やサーバーへのログ送信など)を行う猶予がないことです。したがって、重要なデータを保持している場合は、terminateを呼ぶ前にメッセージ通信(postMessage)でデータの保存を促すのがベストプラクティスです。

サンプルプログラム

以下のコードは、Workerを起動し、3秒後に強制終了させる一連の流れです。

// メインスレッド側
const worker = new Worker(‘worker.js’);

// Workerからのメッセージを受信
worker.onmessage = (e) => {
console.log(‘Workerから受信:’, e.data);
};

// 3秒後にWorkerを強制終了する
setTimeout(() => {
console.log(‘Workerを終了します…’);
// terminateメソッドでスレッドを即座に破棄
worker.terminate();
console.log(‘Workerが終了しました。’);
}, 3000);

// worker.jsの内容
let count = 0;
setInterval(() => {
count++;
// メインスレッドへ定期的にデータを送信
self.postMessage(`カウント: ${count}`);
}, 500);

応用・注意点

現場での開発において陥りやすいのが、terminateを呼んだ後に再びそのWorkerインスタンスを使おうとするケースです。terminate後のWorkerインスタンスは再利用できません。再度処理を実行したい場合は、新しいインスタンス(new Worker())を生成する必要があります。

また、Reactなどのフレームワークで利用する場合、コンポーネントのアンマウント時に必ずterminateを呼ぶように`useEffect`のクリーンアップ関数内で制御することを忘れないでください。これを怠ると、コンポーネントが破棄されてもWorkerがバックグラウンドで動き続け、予期せぬ挙動やメモリ消費の増大を招く可能性があります。

タイトルとURLをコピーしました