JavaScriptプログラムに関する各種メモ書き

Web Workerの基本

Web Workerのライフサイクル

  1. 作成と初期化

    // メインスレッド
    const worker = new Worker('worker.js');
    
  2. 実行状態

    • WorkerはメインスレッドとはUIをブロックすることなく並行して動作します
    • 独自のグローバルスコープ(WorkerGlobalScope)を持ちます
  3. 終了

// メインスレッドからの終了
worker.terminate();

// Worker内からの終了
self.close();

主要なイベント

メインスレッド側のイベント

1 . message

worker.addEventListener('message', (event: MessageEvent) => {
  console.log('Workerからデータを受信:', event.data);
});

2 . error

worker.addEventListener('error', (error: ErrorEvent) => {
  console.error('Workerでエラーが発生:', error.message);
});

// または
worker.onerror = (error: ErrorEvent) => {
  console.error('Workerでエラーが発生:', error.message);
};

3 . messageerror

worker.addEventListener('messageerror', (event: MessageEvent) => {
  console.error('メッセージのデシリアライズに失敗:', event);
});

Worker側のイベント

1 . message

self.addEventListener('message', (event: MessageEvent) => {
  const receivedData = event.data;
  // データ処理
  self.postMessage(processedData);
});

2 . error

self.addEventListener('error', (error: ErrorEvent) => {
  console.error('エラーが発生:', error.message);
});

データ通信

1 . メインスレッドからWorkerへ

// 基本的なデータ送信
worker.postMessage({ type: 'START', payload: data });

// 転送可能オブジェクトの転送
const arrayBuffer = new ArrayBuffer(1024);
worker.postMessage({ buffer: arrayBuffer }, [arrayBuffer]);

2 . WorkerからメインスレッドへのデータチャンネルとしてMessageChannelを使用する例

type MessageChannelConfig = {
  port1: MessagePort;
  port2: MessagePort;
};

// メインスレッド
const channel = new MessageChannel();
worker.postMessage({ type: 'CONNECT' }, [channel.port2]);

channel.port1.onmessage = (event: MessageEvent) => {
  console.log('チャンネル経由でメッセージを受信:', event.data);
};

// Worker側
self.addEventListener('message', (event: MessageEvent) => {
  if (event.data.type === 'CONNECT') {
    const port = event.ports[0];
    port.postMessage('接続確立');
  }
});

重要な注意点

  1. 利用可能なAPI

    • WorkerはDOMにアクセスできません
    • windowオブジェクトの代わりにselfを使用します
    • XHR、Fetch、WebSocket、IndexedDBなどは利用可能です
  2. メモリ管理

    • 大きなデータを転送する場合はtransferable objectsを使用することで、コピーではなく所有権の転送が可能です
    • ArrayBuffer、MessagePort、ImageBitmapなどが転送可能です
  3. エラーハンドリング

// Worker側での包括的なエラーハンドリング
self.addEventListener('error', (error: ErrorEvent) => {
  self.postMessage({
    type: 'ERROR',
    error: {
      message: error.message,
      filename: error.filename,
      lineno: error.lineno,
      colno: error.colno
    }
  });
});
No.2588
02/13 10:02

edit