refactor: replace polling with fetch-based service worker readiness check

Replace the previous message-based polling mechanism for page reload on service worker activation with a fetch request to a dedicated endpoint. This improves reliability and efficiency by directly querying the service worker's state instead of using intervals and postMessage events. The new approach checks for WebAssembly module readiness via ACK/NAK responses, reducing unnecessary reloads and potential race conditions.

lemon-mint committed Oct 31, 2025 at 21:21 UTC c9dc381872ef017a58cad442e20b3e91e80f09df
2 files changed +34 -32
cmd/webclient/index.html
+17 -17
@@ -18,23 +18,6 @@
18
19 showStatus('Registering Service Worker...', 'loading');
20
21 - let reloadOnce = true;
22 -
23 - navigator.serviceWorker.addEventListener('message', (event) => {
24 - console.log(event.data);
25 - if (event.data && event.data.type === 'RELOAD_PAGE') {
26 - if (reloadOnce) {
27 - reloadOnce = false;
28 - window.location.reload();
29 - }
30 - }
31 -
32 - if (event.data && event.data.type === 'UPDATE_MSG') {
33 - showStatus(event.data.msg, 'info');
34 - }
35 - }
36 - );
37 -
21 // Register service worker
22 const registration = await navigator.serviceWorker.register('/service-worker.js', {
23 scope: '/'
@@ -43,6 +26,23 @@
26 } catch (error) {
27 showStatus('Service Worker registration failed: ' + error.message, 'error');
28 }
29 +
30 + const reloadFn = async () => {
31 + const resp = await fetch('/e8c2c70c-ec4a-40b2-b8af-d5638264f831');
32 + const text = await resp.text();
33 + if (text === 'ACK-e8c2c70c-ec4a-40b2-b8af-d5638264f831') {
34 + showStatus('Service Worker is ready.', 'success');
35 + window.location.reload();
36 + } else if (text === 'NAK-e8c2c70c-ec4a-40b2-b8af-d5638264f831'){
37 + setTimeout(reloadFn, 100);
38 + } else {
39 + showStatus('Something went wrong.', 'error');
40 + setTimeout(()=>{
41 + window.location.reload();
42 + }, 1000);
43 + }
44 + }
45 + reloadFn();
46 }
47
48 function showStatus(message, status) {
cmd/webclient/service-worker.js
+17 -15
@@ -17,6 +17,8 @@ async function init() {
17 }
18
19 async function runWASM() {
20 + if (typeof __go_jshttp !== 'undefined') return;
21 +
22 const go = new Go();
23 const cache = await caches.open("WASM_Cache_v1");
24 let wasm_file;
@@ -42,33 +44,33 @@ self.addEventListener('install', (e) => {
44 e.waitUntil(LoadCache());
45 });
46
45 -async function sendMsg(data) {
46 - const clients = await self.clients.matchAll({ type: 'window' });
47 - clients.forEach(client => {
48 - client.postMessage({ type: 'RELOAD_PAGE' });
49 - });
50 -}
51 -
47 self.addEventListener('activate', async (e) => {
53 - await sendMsg({ type: 'UPDATE_MSG', msg: 'Please wait while starting the WebAssembly module...' });
48 await init();
49 await self.clients.claim();
56 -
57 - setInterval(async () => {
58 - if (typeof __go_jshttp == 'undefined') return;
59 -
60 - console.log("Reloading page...")
61 - sendMsg({ type: 'RELOAD_PAGE' });
62 - }, 1000);
50 });
51
52 self.addEventListener('fetch', async (e) => {
53 console.log(e.request);
54 + const url = new URL(e.request.url);
55 +
56 + if (url.origin !== self.location.origin) {
57 + e.respondWith(fetch(e.request));
58 + return;
59 + }
60
61 if (typeof __go_jshttp == 'undefined') {
62 await init();
63 }
64
65 + if (url.pathname === '/e8c2c70c-ec4a-40b2-b8af-d5638264f831') {
66 + if (typeof __go_jshttp == 'undefined') {
67 + e.respondWith(new Response("NAK-e8c2c70c-ec4a-40b2-b8af-d5638264f831", { status: 500 }))
68 + return;
69 + }
70 + e.respondWith(new Response("ACK-e8c2c70c-ec4a-40b2-b8af-d5638264f831", { status: 200 }));
71 + return;
72 + }
73 +
74 if (__go_jshttp) {
75 e.respondWith((async () => {
76 try {