【JavaScript入門】Shared Worker

Shared Worker は 複数ページ/タブ間で 1 本だけ起動される共通スレッド です。
同一オリジン内なら、開いているページが何枚あっても 単一インスタンス を共有できるため、

  • ウィンドウ間でのリアルタイム同期
  • 重量級キャッシュや WebSocket 接続の一本化
    などで威力を発揮します。シンタックスは通常 Worker と似ていますが、port 経由 の通信になる点が大きな違いです。

1.Worker の種類とスコープ

種類スレッド数共有範囲通信 API
Dedicated Workerページごとに 1 本共有なしpostMessage / onmessage
Shared Workerオリジンごとに 1 本同一オリジンの全タブport.postMessage / port.onmessage
Service Workerオリジンごとに 1 本ネットワーク・オフライン制御postMessage / onmessage

2.基本 API

立場生成/接続送信受信
ページnew SharedWorker("worker.js")worker.port.postMessage(data)worker.port.onmessage = e => …
Workeronconnect = e => { const p = e.ports[0]; … }port.postMessage(data)port.onmessage = e => …

port.start() はモダンブラウザで自動呼び出しされるため省略可能です。

3.サンプル構成

app3/
├─ web-worker/
│  ├─ shared-worker.html(各ページから接続)
│  └─ shared-worker.js(共通スレッド)
└─ index.js   ← Express サーバー("Fetch APIで通信をする"で使用したものと同じ)

4.サンプルプログラム

4.1. shared-worker.js(共通スレッド)

// カウンタを全ページで共有
let counter = 0;

onconnect = e => {
  const port = e.ports[0];

  port.onmessage = ev => {
    console.log("@worker 受信:", ev.data);      // Worker 側ログ
    port.postMessage(`返信! ${++counter}`);     // ページへ返信
  };
};

4.2. shared-worker.html(各ページから接続)

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8" />
  <title>🤝 Shared Worker デモ</title>
  <style>
    body{font-family:"Segoe UI",sans-serif;margin:2rem;background:#f9fbff}
    h1{text-align:center;font-size:1.8rem;margin-bottom:1rem}
    button{padding:.6rem 1.2rem;border:none;border-radius:6px;
           background:#0078d4;color:#fff;font-weight:bold;cursor:pointer}
    button:hover{opacity:.85}
    #log{white-space:pre-line;border:1px solid #ccc;background:#fff;
         border-radius:8px;margin-top:1rem;padding:1rem;min-height:6rem}
  </style>
</head>
<body>
  <h1>🤝 Shared Worker デモ</h1>
  <button id="sendBtn">メッセージ送信</button>
  <div id="log">ここに結果が表示されます</div>

  <script>
  const log = txt => document.getElementById("log").textContent += txt + "\n";

  // Shared Worker へ接続
  const worker = new SharedWorker("shared-worker.js");

  // 受信
  worker.port.onmessage = e => log("▶ 受信: " + e.data);

  // 送信ボタン
  document.getElementById("sendBtn").onclick = () => {
    log("● 送信: こんにちは");
    worker.port.postMessage("こんにちは");
  };
  </script>
</body>
</html>

4.3. index.js の作成

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

ファイル名: 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/"));

5.動作確認手順

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

移動例:

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

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

node .

5.3. ブラウザで複数のタブを開き、各々のURLに「http://localhost:3000/web-worker/shared-worker.html」を入力する

各々のタブで「メッセージ送信」をクリックすると

▶ 受信: 返信! 1 ← タブ1
▶ 受信: 返信! 2 ← タブ2
▶ 受信: 返信! 3 ← タブ2

のように カウンタが連番 で増え、単一 Worker が共有されていることが分かります。

6.ポイント解説

  • 接続イベント onconnect
    Shared Worker は “接続” ごとに onconnect が発火し、event.ports[0] でページ専用の MessagePort を取得。
  • 終了管理
    ページが閉じても他タブが残っていれば Worker は存続。完全に不要になったらページ側で worker.port.close() を呼ぶと良い。
  • ユースケース
    ・WebSocket や IndexedDB を 1 つに集約
    ・頻繁なポーリングを複数タブで共有して省リソース
    ・タブ間チャット・通知のリアルタイム同期

まとめ

 Shared Worker を使うと “ブラウザ内のマイクロサービス” のように中央スレッドを置き、複数ページをまたいでステートやコネクションを共有できます。
new SharedWorkerport.postMessage / port.onmessage という最小 API を押さえ、
リアルタイム連携やリソース節約にぜひ活用してみましょう。