Workers - alexanderteplov/computer-science GitHub Wiki

Web workers, Service workers

Web workers

Web workers can be used to offload pretty much any heavy processing from the main thread. A great example is the image processing web application, Squoosh, which uses web workers to handle image manipulation tasks, leaving the main thread available for the user to interact with the application without interruption.

You can't directly manipulate the DOM from inside a worker, or use some default methods and properties of the window object. E.g., localStorage, sessionStorage. But you can use a large number of items available under the window, including WebSockets, and data storage mechanisms like IndexedDB.

Web workers are created using the Web Workers API. After creating a dedicated Javascript file for our worker, we can add it as a new Worker.

/* main.js */

const myWorker = new Worker('worker.js');

Like all workers, web workers do not have access to the DOM, which means that any information needed will have to be passed between the worker and the main script using window.postMessage().

/* main.js */

// Create worker
const myWorker = new Worker('worker.js');

// Send message to worker
myWorker.postMessage('Hello!');

// Receive message from worker
myWorker.onmessage = function(e) {
  console.log(e.data);
}

In our worker script, we can listen for messages from the main script, and return a response.

/* worker.js */

// Receive message from main file
self.onmessage = function(e) {
  console.log(e.data);

  // Send message to main file
  self.postMessage(workerResult);
}

Service workers

Service workers are a type of workers that serve the explicit purpose of being a proxy between the browser and the network and/or cache.

They are designed to be fully async; as a consequence, APIs such as synchronous XHR and Web Storage can't be used inside a service worker.

Service workers only run over HTTPS, for security reasons.

Cache represents the storage for Request/Response object pairs that are cached as part of the ServiceWorker life cycle.

Like web workers, service workers are registered in the main javascript file, referencing a dedicated service worker file

/* main.js */

navigator.serviceWorker.register('/service-worker.js');

Unlike regular web workers, service workers have some extra features that allow them to fulfil their proxy purpose. Once they are installed and activated, service workers are able to intercept any network requests made from the main document.

/* service-worker.js */

// Install
self.addEventListener('install', function(event) {
    // ...
});

// Activate
self.addEventListener('activate', function(event) {
    // ...
});

// Listen for network requests from the main document
self.addEventListener('fetch', function(event) {
    // ...
});

Once intercepted, a service worker can, for example, respond by returning a document from the cache instead of going to the network, thereby allowing web applications to function offline!

Worklets

Worklets are very lightweight, highly specific, workers. They enable us as developers to hook into various parts of the browser’s rendering process.

The Paint Worklet allows us to create custom images that can be applied anywhere CSS expects an image, for example as a value to the background-image property.

To create a worklet, as with all workers, we register it in our main javascript file, referencing the dedicated worklet file.

/* main.js */

CSS.paintWorklet.addModule('myWorklet.js');

In our worklet file, we can create a custom image. The paint method works very similarly to the Canvas API. Here’s an example of a simple black-to-white gradient.

/* myWorklet.js */

registerPaint('myGradient', class {
  paint(ctx, size, properties) {
    var gradient = ctx.createLinearGradient(0, 0, 0, size.height / 3);

    gradient.addColorStop(0, "black");
    gradient.addColorStop(0.7, "rgb(210, 210, 210)");
    gradient.addColorStop(0.8, "rgb(230, 230, 230)");
    gradient.addColorStop(1, "white");

    ctx.fillStyle = gradient;
    ctx.fillRect(0, 0, size.width, size.height / 3);
  }
});

Finally, we can use this new worklet in our CSS, and the custom image we created will be applied like any other background image.

div {
    background-image: paint(myGradient);
}

In addition to the Paint Worklet, there are other worklets that hook into other stages of the rendering process. The Animation Worklet hooks into the Composite stage, and the Layout Worklet hooks in to the Layout stage.

Links

⚠️ **GitHub.com Fallback** ⚠️