Home >Web Front-end >JS Tutorial >Some notes on SharedWorkers

Some notes on SharedWorkers

DDD
DDDOriginal
2024-11-04 05:14:02525browse

Some notes on SharedWorkers

I recently needed to implement a shared worker in a project. Though they are super useful, there wasn't much info to be found in the usual places, so here are some pointers that might help searchers from the mysterious future.

Background

SharedWorkers are a special class of WebWorker that can be shared across multiple tabs, windows or other (regular) web workers.

In my application, I needed a process which would poll for new application events (for example, a customer completing a purchase), and show a notification (using the Notifications API) to logged in administrators (or more specifically, those logged in administrators who had chosen to receive notifications).

An administrator could have the application open in several tabs or windows, so it would be wasteful to have each tab polling for new events. I only wanted one notification per event, regardless of the number of open tabs or windows.

SharedWorker to the rescue! Each of the open tabs or windows shares a single worker, which polls in the background, and shows just one notification per new event.

Creating a shared worker with Vite

The first challenge was loading the shared worker in my Vite-based setup.

If you're running Vite in dev mode, Vite serves the script from a different domain and port (eg http://[::1]:5173/), which won't work, because shared workers must obey the same-origin policy.

I tried various Vite workarounds for web workers:

  • The official Vite web worker method doesn’t work for shared workers due to the same-origin policy requirement.
  • Blob URLs aren't supported for shared workers.
  • Inlining the worker as a base64 string doesn’t work because the browser treats them as different workers: fine for web workers, but not for shared workers.

In the end, I created a new route to serve the script either from the resources directory in dev, or the build directory in staging and live environments.

Route::addRoute('GET', '/notifications-shared-worker.js', function () {
    // If in dev environment, send the file from the resources folder
    if (app()->environment('local')) {
        return response()->file(resource_path('js/notificationWatcherWorker.js'), ['Content-Type' => 'text/javascript']);
    } else {
        // Otherwise, send the file from the public folder
        return response()->file(public_path('build/assets/notificationWatcherWorker.js'), ['Content-Type' => 'text/javascript']);
    }
});

I then create the shared worker with that route as the URL:

const worker = new SharedWorker('/notifications-shared-worker.js');

Debugging the Shared Worker

You'll quickly find that any syntax or runtime errors in your shared worker don't appear in your devtools. Nor do any console log/warn/info calls.

This one is easy, paste chrome://inspect/#workers into your URL bar, find the shared worker and click on 'inspect'. Now you have a devtools window just for the shared worker.

Communicating back to the main tab or window

To communicate back to the ‘parent’ tab, use the port.postMessage method, as described in the MDN SharedWorker documentation.

However, the example code only allows communication with the most recent ‘parent’ tab/window because it overwrites the communication port reference each time a parent connects.

Instead, store an array of ports, and add each new port to the array when a new ‘parent’ connects.

Route::addRoute('GET', '/notifications-shared-worker.js', function () {
    // If in dev environment, send the file from the resources folder
    if (app()->environment('local')) {
        return response()->file(resource_path('js/notificationWatcherWorker.js'), ['Content-Type' => 'text/javascript']);
    } else {
        // Otherwise, send the file from the public folder
        return response()->file(public_path('build/assets/notificationWatcherWorker.js'), ['Content-Type' => 'text/javascript']);
    }
});

Then, send a message to all the parent pages like this:

const worker = new SharedWorker('/notifications-shared-worker.js');

The above is the detailed content of Some notes on SharedWorkers. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn