2HAASStart a project
All posts

Code Snippets

Web Workers: move heavy work off the main thread

Heavy JavaScript freezes the page because it shares a thread with the interface. A Web Worker runs that work in the background. A working example and the limits to know.

The 2HAAS team2 min read

JavaScript in the browser runs on the same thread that draws the page and handles clicks. Apply a filter to a large image there and the interface freezes until it finishes: no scrolling, no button feedback, nothing.

A Web Worker is a second thread. It runs a script in the background and talks to the page through messages, so the interface stays free.

A working example

The page creates the worker, sends it the pixels and waits for the result.

// main.js
const worker = new Worker(new URL("./filter.worker.js", import.meta.url), { type: "module" });

function applyFilter(imageData) {
  const { width, height, data } = imageData;
  // The second argument transfers the buffer instead of copying it
  worker.postMessage({ pixels: data.buffer, width, height }, [data.buffer]);
}

worker.addEventListener("message", (event) => {
  drawResult(new Uint8ClampedArray(event.data));
});

worker.addEventListener("error", (event) => {
  showError(event.message);
});

The worker does the slow part.

// filter.worker.js
self.addEventListener("message", (event) => {
  const { pixels, width, height } = event.data;
  const result = grayscale(new Uint8ClampedArray(pixels), width, height);
  self.postMessage(result.buffer, [result.buffer]);
});

function grayscale(data) {
  for (let i = 0; i < data.length; i += 4) {
    const value = 0.299 * data[i] + 0.587 * data[i + 1] + 0.114 * data[i + 2];
    data[i] = data[i + 1] = data[i + 2] = value;
  }
  return data;
}

While the worker runs, the user can keep scrolling and clicking.

What a worker cannot do

  • No DOM access. A worker cannot read or change the page. It computes and returns a result.
  • No shared variables. Everything passes through postMessage.
  • Messages are copied. Large objects take time to copy. Transfer an ArrayBuffer, as above, and ownership moves without a copy.

Good candidates

  • image and video processing,
  • parsing large JSON or CSV files,
  • building a search index,
  • hashing and encryption,
  • heavy calculations for charts or simulations.

A quick task is a poor candidate. Starting a worker and passing messages has a cost of its own, so save workers for work that would block the page for a noticeable time.

Practical tips

  1. Reuse workers. Create one and send it many jobs. Creating a worker for each task wastes startup time.
  2. Stop what you no longer need. worker.terminate() ends a worker when the user leaves the screen.
  3. Handle errors. Listen for the error event, or a failure in the background goes unseen.
  4. Consider a helper library. Comlink wraps the message passing so that calling a worker looks like calling an async function.

Workers are one way to keep a page responsive. For the others, see keeping the main thread free.

Keep reading

  1. Code Snippets2 min read

    Intersection Observer: react when elements scroll into view

    Scroll listeners that measure element positions are slow and fiddly. Intersection Observer tells you when an element enters the viewport, with a few lines of code.

  2. Guides2 min read

    How to reduce JavaScript bundle size

    Every kilobyte of JavaScript is downloaded, parsed and run before a page responds. Measure the bundle, split it by route, lazy load the rest and trim dependencies.

  3. Tech Tips2 min read

    JavaScript performance: keep the main thread free

    A page can load fast and still feel slow. Batch DOM updates, debounce noisy events and break up long tasks to keep the interface responsive.

Tell us what’s in the way.

A few lines is enough. You get a candid yes, a candid no, or a sharper question.

  • Working software in week four
  • A reply in one business day
  • Handover is the deliverable

Prefer email? [email protected]

The problem, who it is for, and what is in the way right now.

One business day to a real reply. No sales sequence, no call required.