demo · v140
Module Worker Chain
A chain of workers created from blob URLs — each spawning the next. Before Chrome 140 only the first-generation worker inherited the page's service worker controller; child blob workers bypassed the SW entirely. Chrome 140 fixes the full chain.
Service Worker note
This demo works best on a page controlled by a SW. If the "page controlled" badge below shows "no", the workers will still launch but SW interception badges will reflect no SW present. Reload after a SW is installed to see the full chain effect.
SW: checking...
controller: checking...
Page (window)
→ creates blob URL →
Worker A (blob:)
→ spawns blob URL →
Worker B (blob:)
↕ SW intercepts all fetches post-140
Service Worker
Chain log — each entry shows context + SW controller presence:
Press "Start chain" to launch the worker chain.
pre-140 — child blob workers uncontrolled
// Worker A (blob): inherits controller ✓
// Worker B (blob, child of A): NO controller ✗
// Fetches from B bypass the SW entirely
const code = `
const child = new Worker(
URL.createObjectURL(blob)
);
// child has no SW controller
`;
const urlA = URL.createObjectURL(
new Blob([code], {type:'text/javascript'})
);
new Worker(urlA); // A ok, B broken
Chrome 140 — full chain inherits
// Worker A (blob): inherits controller ✓
// Worker B (blob, child of A): inherits ✓
// All fetches in the chain hit the SW
const code = `
const child = new Worker(
URL.createObjectURL(blob)
);
// child now inherits controller too
`;
const urlA = URL.createObjectURL(
new Blob([code], {type:'text/javascript'})
);
new Worker(urlA); // entire chain controlled
// Chain: page → blob Worker A → blob Worker B
const workerBCode = `
self.onmessage = async (e) => {
const ctrl = !!navigator?.serviceWorker?.controller;
self.postMessage({ ctx: 'Worker B (blob child)', ctrl });
};
`;
const workerACode = `
self.onmessage = async (e) => {
const ctrl = !!navigator?.serviceWorker?.controller;
self.postMessage({ ctx: 'Worker A (blob)', ctrl });
// spawn child blob worker — pre-140: child had no controller
const bBlob = new Blob([${JSON.stringify('...')}], { type: 'text/javascript' });
const childWorker = new Worker(URL.createObjectURL(bBlob));
childWorker.onmessage = (ce) => self.postMessage(ce.data);
childWorker.postMessage('go');
};
`;
const urlA = URL.createObjectURL(
new Blob([workerACode], { type: 'text/javascript' })
);
const wA = new Worker(urlA);
wA.postMessage('go');
see also
- SharedWorker blob inherits controller — feature index
- Blob Controller — single worker probe
- SW Fetch Interception — fetch flow
- ChromeStatus entry
- Spec: control-and-use-worker-client