Service Worker- Messaging Channel

A ServiceWorker continues to run in the background even after the user has navigated away from the site. It requires a secure context, ie. HTTPS.

Worker Type Lifespan
Dedicated Web Worker Until closing of tab or navigation to another page.
Shared Worker Until closing of all tabs of the site on a browser.
Service Worker About one minute after the closing of all tabs of the site on a browser, on a desktop PC.
(as of 3 Oct, 2020)
Launch the webpage below on the FULL-screen mode. Then close the tab without closing the browser. After some time, relaunch the HTML file on the browser again. You will see that the enumeration will continue, ie. number not starting from 0.

Note the scope of the service worker. For simpliciy, below, the webpage is served over the same path as the service worker .js script.

RESETRUNFULL
// /shared/service.js
self.addEventListener('install' , e => e.waitUntil(self.skipWaiting()));
self.addEventListener('activate', e => e.waitUntil(self.clients.claim()));
var i = 0;
self.addEventListener('message',
   function (ev){
      setTimeout(()=>{ev.ports[0].postMessage(i++);},300);
   }
);

<!DOCTYPE html><html><body>
<p></p>
<script>
function sendMessage(e){
   document.querySelector('p').innerHTML += "<br/>" + e.data;
   var mc = new MessageChannel();
   mc.port1.onmessage = sendMessage;
   navigator.serviceWorker.controller
            .postMessage(e.data+1,[mc.port2]);
}
navigator.serviceWorker.register('service.js', {scope: './'}).then(reg => {
   var mc = new MessageChannel();
   mc.port1.onmessage = sendMessage;
   var serviceWorker;
   if (reg.installing) {
      serviceWorker = reg.installing;
      document.querySelector('p').innerHTML = 'installing';
   } else if (reg.waiting) {
      serviceWorker = reg.waiting;
      document.querySelector('p').innerHTML = 'waiting';
   } else if (reg.active) {
      serviceWorker = reg.active;
      document.querySelector('p').innerHTML = 'active';
      serviceWorker.postMessage(null,[mc.port2]);
   }
   if (serviceWorker) {
      serviceWorker.addEventListener('statechange', function (e) {
         if (e.target.state=='activated'){
            navigator.serviceWorker.controller.postMessage(null,[mc.port2]);
            document.querySelector('p').innerHTML = 'activated';
         }
      });
   }
}).catch((error) => {
   console.log('Registration failed with ' + error);
});
</script></body></html>
The claim() method of the Clients interface allows an active service worker to set itself as the controller for all clients within its scope. This triggers a "controllerchange" event on navigator.serviceWorker in any clients that become controlled by this service worker. When a service worker is initially registered, pages won't use it until the next load. The claim() method causes those pages to be controlled immediately. Be aware that this results in your service worker controlling pages that are loaded regularly over the network, or possibly via a different service worker.

The ServiceWorker.skipWaiting() method ensures that any new versions of a service worker will take over the page and become activated immediately.