Shared Worker

While a dedicated web worker can be repeatedly spawned and nested by one webpage, a shared worker can be shared by different webpages from the same origin (scheme://host:port) during the same session across multiple tabs on a browser. Repeatedly instantiating a SharedWorker with the same script will only result in one thread being spawned, unlike the case for a dedicated web worker.

Try clicking the first 'initiate' button and then the next 'initiate' button below it. You will see that after the initiation, on the second output, the enumeration won't start from 0.
RESETRUNFULL
// /shared/shared.js
const ports = [];
onconnect = function (ev) {
    let port = ev.ports[0];
    port.onmessage = (e) => {
        setTimeout(()=>{
            ports.forEach(p=>p.postMessage([e.data, ev.ports.length]));
        },300);
    }
    ports.push(port);
}

<!DOCTYPE html><html><body style="height:80px">
<p></p>
<button onclick="init()">Initiate</button>
<script>
  function init() {
    var w = (new SharedWorker('/shared/shared.js')).port;
    w.onmessage = e=>{
        document.querySelector("p").innerHTML = e.data;
        w.postMessage(e.data[0]+1);
    };
    w.start();
    w.postMessage(0);
  }
</script></body></html>

RESETRUNFULL
// /shared/shared.js
const ports = [];
onconnect = function (ev) {
    let port = ev.ports[0];
    port.onmessage = (e) => {
        setTimeout(()=>{
            ports.forEach(p=>p.postMessage([e.data, ev.ports.length]));
        },300);
    }
    ports.push(port);
}

<!DOCTYPE html><html><body style="height:80px">
<p></p>
<button onclick="init()">Initiate</button>
<script>
  function init(v) {
    var w = (new SharedWorker('/shared/shared.js')).port;
    w.start();
    w.onmessage = e=>{
        document.querySelector("p").innerHTML = e.data;
    };
  }
</script></body></html>

SharedWorker also works across iframes and dedicated web workers.

In case you need to pass the port around, you will need to include it inside an array in the second parameter of postMessage(), as the port is a Transferable object. If the ownership of a Transferrable object is transferred, it becomes unusable (neutered) in the context it was sent from and becomes available only to the worker it was sent to. Transferable objects are instances of classes like ArrayBuffer, MessagePort, or ImageBitmap objects that can be transferred.

b.postMessage({port:a}, [a]);

A shared worker lasts until the visitor leaves the website entirely on a browser.