Shared Web Workers are designed to allow multiple pages from the same site (origin) to share a single Web Worker.
However, it's not clear to me from the spec (or other tutorials and information on Shared Workers) whether the Shared Worker will persist if you have only one window/tab from the site and you navigate to another page on the same site.
This would be most useful in the case of a WebSocket connection from the Shared Worker that stays connected as the site is navigated. For example, imagine a stock ticker or chat area that would persist (without having to reconnect the WebSocket) even while the site is navigated.
Web Workers run in an isolated thread. As a result, the code that they execute needs to be contained in a separate file.
A shared worker can work with multiple connections. It posts messages to ports to allow communication between various scripts. A dedicated worker on the other hand is simply tied to its main connection and cannot post messages to other scripts (workers).
A web worker is a JavaScript program running on a different thread, in parallel with main thread. The browser creates one thread per tab. The main thread can spawn an unlimited number of web workers, until the user's system resources are fully consumed.
The SharedWorker interface represents a specific kind of worker that can be accessed from several browsing contexts, such as several windows, iframes or even workers. They implement an interface different than dedicated workers and have a different global scope, SharedWorkerGlobalScope .
I have done some testing to find out the answer to this in practice.
Firefox does not yet support creating WebSocket connections from Web Workers: https://bugzilla.mozilla.org/show_bug.cgi?id=504553 So Firefox is not relevant until that bug is resolved.
IE 10 doesn't have support for Shared Web Workers so it's not relevant either. So that leaves Chrome.
Here is an example to test shared web workers.
First the HTML:
<!DOCTYPE html>
<html>
<body>
<a href="shared.html">reload page</a>
<script>
var worker = new SharedWorker("shared.js");
worker.port.addEventListener("message", function(e) {
console.log("Got message: " + e.data);
}, false);
worker.port.start();
worker.port.postMessage("start");
</script>
</body>
</html>
Then the implementation of the shared worker itself in shared.js
:
var connections = 0;
self.addEventListener("connect", function(e) {
var port = e.ports[0];
connections ++;
port.addEventListener("message", function(e) {
if (e.data === "start") {
var ws = new WebSocket("ws://localhost:6080");
port.postMessage("started connection: " + connections);
}
}, false);
port.start();
}, false);
Test results in Chrome 20 (the answer):
When the page is loaded simultaneously in two separate tabs, the connection count grows each time one of the pages is reloaded or the self-referential link is clicked.
If only a single instance of the page is loaded then the connection count never changes when the page is reloaded or the link is clicked.
So, in Chrome 20: Shared Web Workers do not persist across page reloads and link navigation clicks.
It seems like this is basically the same problem as the question 'What happens to an HTML5 web worker thread when the tab is closed while it's running?'. I think the key part of the spec is this statement:
User agents may invoke the "kill a worker" processing model on a worker at any time, e.g. in response to user requests, in response to CPU quota management, or when a worker stops being an active needed worker if the worker continues executing even after its closing flag was set to true.
An 'active needed worker' is defined as follows:
A worker is said to be an active needed worker if any of the Document objects in the worker's Documents are fully active.
So, as I understand it, if all the windows referencing a worker are closed then the browser is required by the spec to terminate the worker, but not immediately. Depending on it persisting will therefore be unreliable even if it appears to work occasionally.
In your example my approach would be to load the whole site by Ajax - you're not going to be able to run the Web Workers if your users have JS disabled anyhow, then use the History API to make the user's page address correspond to the actual page (maintaining search engine and non-JS compatibility).
I have had success with a somewhat roundabout technique whereby when I want to go to the next page but maintain the SharedWorker, I open up a (hopefully unobtrusive) popup window that creates the same worker, wait for it to become active and send a message to the original port/window, which then navigates to the new page and then, when that page loads, closes the popup. This strategy maintains at least one active connection at all times, so the worker never decides to shut down.
This technique seems to be fairly robust so far. Although seeing the popup is somewhat annoying, it's a reasonable compromise for some use cases.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With