TypeScriptにおけるWeb Worker
この記事ではTypeScriptにおけるWeb Workerについて説明します。
Web Worker
の概念から様々な使い方のポイントをサンプルと共に学べます。
YouTube Video
TypeScriptにおけるWorker
TypeScriptにおけるWorker
は、JavaScriptのWeb Workers APIを活用して、メインスレッドとは別にバックグラウンドで処理を行うための仕組みです。これにより、重い計算や非同期タスクがユーザーインターフェースの操作に影響を与えることなく実行できるようになります。
Worker
はメインスレッド(UIスレッド)と並行して動作し、メッセージを通じてスレッド間でデータをやり取りすることができます。TypeScriptでも、型安全なコードを書きつつWorker
を使用することができます。
基本的なWorkerの使い方
-
Workerの作成
Worker
インスタンスを作成し、指定したスクリプトを実行します。通常、スクリプトは別ファイルで定義します。 -
メッセージのやり取り
メインスレッドと
Worker
スレッドの間で、postMessage
とonmessage
を使ってメッセージを送受信します。
例: 基本的なWorkerの実装
- worker.ts: Worker用スクリプト
1// worker.ts
2self.onmessage = (event) => {
3 const data = event.data;
4 const result = data.num1 + data.num2;
5 self.postMessage(result); // Return the result to the main thread
6};
- main.ts: メインスレッドでWorkerを利用するスクリプト
1// main.ts
2const worker = new Worker(
3 new URL('./worker.ts', import.meta.url),
4 { type: 'module' }
5);
6
7worker.onmessage = (event) => {
8 console.log("Result from worker:", event.data); // Receive message from the worker
9};
10
11worker.postMessage({ num1: 10, num2: 20 }); // Send message to the worker
- この例では、
worker.ts
は別スレッドで動作し、num1
とnum2
の和を計算してメインスレッドに返します。メインスレッドは、その結果を受け取ってコンソールに出力します。 type: 'module'
を指定すると、Worker スクリプトが ESモジュール として解釈され、import
、export
が利用可能になります。これにより従来のimportScripts()
を使わずにモジュール構造を扱えます。
TypeScriptでWorkerを使う際のポイント
型定義の追加
TypeScriptでは、メッセージの送受信時に型安全なやり取りを行うために、データの型を定義します。
1// Define data types
2interface WorkerData {
3 num1: number;
4 num2: number;
5}
6
7interface WorkerResult {
8 result: number;
9}
10
11// worker.ts
12self.onmessage = (event: MessageEvent<WorkerData>) => {
13 const data = event.data;
14 const result = data.num1 + data.num2;
15 const message: WorkerResult = { result };
16 self.postMessage(message); // Send the result in a type-safe manner
17};
18
19// main.ts
20const worker = new Worker(new URL('./worker.ts', import.meta.url), { type: 'module' });
21
22// Type the event from the worker
23worker.onmessage = (event: MessageEvent<WorkerResult>) => {
24 console.log("Result from worker:", event.data); // event.data is number
25};
26
27// Send typed data to the worker
28const message: WorkerData = { num1: 10, num2: 20 };
29worker.postMessage(message);
MessageEvent
の型パラメータを指定することで、受け取るデータの型を明確に定義できます。これにより、型安全にデータをやり取りできます。
WebpackやViteの設定
TypeScriptでWorker
を使う場合、Webpack
やVite
のようなバンドラが必要なことがあります。これらのツールを使うことで、Worker
スクリプトを適切にバンドルし、メインスレッドから利用できるようにします。
たとえば、Vite
を使う場合、import.meta.url
を使って正しくWorker
をインポートします。
1const worker = new Worker(new URL('./worker.ts', import.meta.url), { type: 'module' });
- これにより、バンドルされた
Worker
スクリプトが正しく読み込まれ、Worker
を活用した処理が可能になります。
メッセージングと並行処理の注意点
-
データのコピー
メインスレッドと
Worker
スレッドの間でメッセージを送受信する際、データはコピーされます。オブジェクトなどの複雑なデータを扱う場合、効率を考慮する必要があります。大きなデータを頻繁にやり取りすると、パフォーマンスが低下する可能性があります。 -
Transferable
オブジェクトArrayBuffer
のような一部のオブジェクトはTransferable
オブジェクトと呼ばれます。Transferable
オブジェクトは、メッセージング時にコピーされるのではなく、所有権をWorker
側に譲渡することができます。これにより、データのコピーによるオーバーヘッドを避けることができます。
1const worker = new Worker(new URL('./worker.ts', import.meta.url), { type: 'module' });
2
3const buffer = new ArrayBuffer(1024);
4worker.postMessage(buffer, [buffer]); // Transfer ownership to the Worker
5
6console.log(buffer.byteLength); // 0 (ownership moved)
-
worker.postMessage()
の第2引数に[buffer]
を渡すことで、buffer
がコピーされるのではなくWorker
に「移譲」されます。 -
この後、メインスレッド側の
buffer
は空(byteLength
が0)になり、Worker
側だけが使える状態になります。
Workerの終了
Worker
は使い終わったらメモリの消費を抑えるために終了させる必要があります。terminate
メソッドを使うことでWorker
を終了させることができます。
1const worker = new Worker(new URL('./worker.ts', import.meta.url), { type: 'module' });
2// ...
3
4worker.terminate(); // Terminate the Worker
- このコードは、
terminate
メソッドを使ってWorker
を終了させる処理を行っています。
Workerの例外処理
Worker
内でエラーが発生した場合、onerror
イベントを使ってエラーハンドリングができます。
1const worker = new Worker(new URL('./worker.ts', import.meta.url), { type: 'module' });
2
3worker.onerror = (error) => {
4 console.error("Error in Worker:", error.message);
5};
- このコードは、
Worker
内で発生したエラーをonerror
イベントで捕捉して処理しています。
まとめ
TypeScriptでWorker
を使うことで、重い処理をバックグラウンドで実行しつつ、メインスレッドをスムーズに保つことが可能です。型定義を活用することで、メッセージのやり取りも型安全に行えます。データのやり取りやスレッドの管理に注意しつつ、パフォーマンスの向上や効率的な並行処理を実現できます。
YouTubeチャンネルでは、Visual Studio Codeを用いて上記の記事を見ながら確認できます。 ぜひYouTubeチャンネルもご覧ください。