Consider the following code:
// Precondition: `registration`is a valid ServiceWorkerRegistration object with
// a valid "active" worker with no pending events
registration.unregister()
.then(function() {
registration.active.postMessage('');
});
"unregistration" involves the following sequence:
- Queue a task to resolve the promise (via Resolve Job Promise)
- If the active worker has no pending events (via Try Clear Registration)
- Terminate the active worker (via Clear Registration)
- Set the worker's "closing" flag to
true
- Set the worker's "closing" flag to
- Queue a task to set the
state
attribute of the active worker to "redundant" (via Update Worker State) - Queue a task to set the registration's
active
property tonull
(via Update Registration State)
- Terminate the active worker (via Clear Registration)
This means the state
attribute is not set until after the promise has been
resolved and any subsequent microtasks processed. Here, the postMessage
invocation is part of such a microtask, so when it references the worker's
state
, it receives the value "active". Execution of the postMessage
algorithm proceeds to step 4, where Run Service Worker is invoked. This creates
a new ServiceWorkerGlobalScope object, effectively undoing the prior invocation
of Terminate Worker.
Chromium's behavior more or less adheres to this interpretation, although the
worker's script is only evaluated one time (I would expect a second evaluation
for that invocation of Run Service Worker). Firefox throws an error named
NS_ERROR_FAILURE
. In either case, this seems like a spec bug--the
"unregister" operation is being interrupted, but the worker state is still
ultimately set to "redundant."