【JavaScript入門】Web Worker

Web Worker はブラウザに “もう一本の JavaScript スレッド” を生み出し、
UI スレッド(メイン)をブロックせずに 重い計算や長時間タスク を並行実行できます。
 Worker とは postMessage でデータを送り、onmessage で受け取る ― たった 2 つの API が核です。本章では API 概観 → ファイル配置 → 動くサンプル の順に学びます。

1.基本 API

機能メインスレッドWorker スレッド
インスタンス生成const w = new Worker("worker.js");
メッセージ送信w.postMessage(data);postMessage(data);
受信ハンドラw.onmessage = e => {…}onmessage = e => {…}
終了w.terminate();close();

※ メッセージは コピー渡し(シリアライズ)になるため、同じオブジェクト参照は共有されません。

どんなとき便利?

  • 画像・音声・動画のフィルタリング
  • 暗号化/データ圧縮など CPU 集約タスク
  • 大量ループでの統計・シミュレーション

2.サンプル構成

app3/
├─ web-worker/
│  ├─ worker-demo.html      ← メイン側
│  └─ calc-worker.js        ← Worker スレッド
└─ index.js   ← Express サーバー("Fetch APIで通信をする"で使用したものと同じ)

3.calc-worker.js(Worker 側)

// メッセージ受信
onmessage = e => {
  const n = e.data;                    // 受け取った数値
  // 重い計算: n 番目までの素数を列挙
  const primes = [];
  let num = 2;
  while (primes.length < n) {
    if (primes.every(p => num % p !== 0)) primes.push(num);
    num++;
  }
  postMessage(primes);                 // 結果を返す
};

4.worker-demo.html(メイン側)

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8" />
  <title>⚙️ Web Worker デモ</title>
  <style>
    body{font-family:"Segoe UI",sans-serif;margin:2rem;background:#f7fbff}
    h1{text-align:center;font-size:1.8rem;margin-bottom:1rem}
    input,button{padding:.5rem .8rem;margin-right:.5rem}
    #log{white-space:pre-line;border:1px solid #ccc;background:#fff;
         border-radius:8px;padding:1rem;margin-top:1rem;min-height:6rem}
  </style>
</head>
<body>
  <h1>⚙️ Web Worker デモ</h1>
  <input id="count" type="number" value="10" min="1" />
  <button id="runBtn">素数を計算</button>
  <div id="log">ここに結果が表示されます</div>

  <script>
  const log = txt => document.getElementById("log").textContent += txt + "\n";
  const worker = new Worker("calc-worker.js");     // Worker 作成

  // Worker から結果を受信
  worker.onmessage = e => {
    log("▶ 結果: " + e.data.join(", "));
  };

  // ボタン: 計算指示を送る
  document.getElementById("runBtn").onclick = () => {
    const n = Number(document.getElementById("count").value);
    log(`● 素数 ${n} 個を計算中…`);
    worker.postMessage(n);                         // メインは止まらない
  };
  </script>
</body>
</html>

4.1. index.js の作成

以下の index.js を作成して、例えば「C:\Users\<ユーザー名>\Desktop\node-js\app3」に保存します。

ファイル名: index.js

// index.js
const express = require("express");
const app = express();

// ルート
app.get("/", (_, res) => res.send("Hello World"));

// 静的ファイル(/net, /web-worker 配下)
[
  { path: "/net",         root: __dirname + "/net" },
  { path: "/web-worker",  root: __dirname + "/web-worker" }
].forEach(opt => app.use(opt.path, express.static(opt.root)));

app.listen(3000, () => console.log("Server started: http://localhost:3000/"));

4.2. PowerShell を起動し、index.js を置いたフォルダへ移動します。

移動例:

PS C:\Users\joeac\Desktop\node-js\app3>

4.3. ターミナルで node . を実行

node .

4.4. ブラウザのURLに「http://localhost:3000/web-worker/worker-demo.html 」を入力

すると 「Hello World」が表示されます。

ブラウザの出力例

ブラウザのURLに「http://localhost:3000/web-worker/worker-demo.html」と入力します。

● 素数 10 個を計算中…
▶ 結果: 2, 3, 5, 7, 11, 13, 17, 19, 23, 29

ページはボタン連打や入力操作を受け付け続け、
重い計算はバックグラウンドで完了後に結果だけ返ってきます。

5.ポイント解説

テーマ解説
ファイル配置Worker は 同一オリジン の別 JS ファイルとして保存し、new Worker("path") で読み込む(ローカルファイル直開きでは動かないため Express などでサーバー起動が必要)
データ転送postMessage はコピー渡し。大量データには structuredClone()Transferable オブジェクトArrayBuffer など)を利用すると高速
エラー処理worker.onerror = e => ... でスレッド内例外を捕捉
終了長期利用しない場合は worker.terminate() でスレッドを開放

まとめ

Web Worker を利用すると 計算負荷を UI スレッドから切り離し スムーズな操作感を保てます。

  • new Worker() で専用スレッド生成
  • postMessage / onmessage でデータ連携
  • メモリ共有はなくコピーが行われる
    という3点を押さえれば、画像加工やデータ解析など “重たい処理” を安心してバックグラウンド実行できます。まずは本サンプルを動かし、メイン UI が固まらないことを体感してみましょう。