DEV Community

Cover image for 🚀 Supercharge Your Web Apps with Web Workers in React and Vue
Obiwan Pelosi
Obiwan Pelosi

Posted on

🚀 Supercharge Your Web Apps with Web Workers in React and Vue

Have you ever noticed your web app freezing for a moment while processing something complex—maybe parsing a huge JSON file, crunching numbers, or resizing an image? 😬

That’s your main thread choking under pressure.

But fear not! There's a superhero in the browser world that can take some of the heavy lifting off your main thread’s shoulders. Meet Web Workers, your friendly background JavaScript buddies.

In this article, we’ll explore how to integrate Web Workers into both React and Vue applications. Let’s make your apps faster, smoother, and more responsive, with some fun along the way!

🧠 Why even use Web Workers?

Javascript is single-threaded which means the browser's main thread is responsible for handling both UI rendering and also logic. This can get "too much" and cause lags especially when performing expensive operations. Web Workers run in a separate thread from the main browser thread. This means they can handle resource-heavy tasks without blocking your UI.

✅ When You Should Use Web Workers

🔁 1. Heavy Computation

If you're performing tasks that take more than a few milliseconds, like:

  • Processing large datasets (e.g., CSV parsing, log processing)

  • Image manipulation (e.g., filters, compression)

  • Cryptographic computations

  • Complex math or simulations

These tasks block the main UI thread if not offloaded.

📈 2. Real-time Data Processing:

When you're streaming and processing real-time data:

  • WebSocket streams (e.g., trading dashboards, multiplayer games)

  • Audio/video analysis

  • IoT sensor data parsing

🔍 3. Machine Learning Inference in the Browser
Using models (like TensorFlow.js or ONNX) can strain the main thread. Running inference in a Web Worker can keep the UI smooth.

🧠 4. Apps Needing Maximum Responsiveness
Apps where UI responsiveness is crucial:

  • Graphic editors

  • Code editors

  • Collaborative tools

🚫 When Not to Use Web Workers

🐣 1. Simple or Short Tasks

Don’t use a worker for trivial operations. Spinning up a Web Worker has a cost, especially for very small jobs—it could be slower than just running the task in the main thread.

🔗 2. If You Need Access to the DOM

Web Workers can’t:

  • Read/write the DOM

  • Access window, document, or localStorage directly.

Use them only for data processing—not UI manipulation.

📦 3. If You’re Already Using Backend Processing

If a task is already handled by a backend service or API, using a worker to process it locally might be redundant or even wasteful.

🔌 4. When Browser Support Is Critical

Web Workers are widely supported, but there may be edge cases (e.g., very old mobile browsers or embedded webviews) where they're unavailable. Test accordingly.

🔨 Web Workers in Action (Vanilla Style)

Before diving into frameworks, let’s get a sense of how Web Workers work.

worker.js

// This runs in a separate thread
self.onmessage = function (event) {
  const data = event.data;
  const result = data * 2; // simulate heavy task
  self.postMessage(result);
};
Enter fullscreen mode Exit fullscreen mode

main.js

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

worker.postMessage(10);

worker.onmessage = function (event) {
  console.log('Result from worker:', event.data); // 20
};
Enter fullscreen mode Exit fullscreen mode

That's it!

⚛️ Using Web Workers in React

Let’s integrate a worker into a React app with Vite. We'll create a component that uses a worker to perform a CPU-heavy calculation.

🔧 Setup

First, create a worker file:

src/workers/counterWorker.js

self.onmessage = function (e) {
  const num = e.data;
  let result = 0;
  for (let i = 0; i < num; i++) result += i;
  self.postMessage(result);
};
Enter fullscreen mode Exit fullscreen mode

🧩 React Component Example

Imagine you have a component that has to loop over 10 million items

HeavyCounter.jsx

import { useState } from 'react';

export default function HeavyCounter() {
  const [result, setResult] = useState(null);
  const [loading, setLoading] = useState(false);

  const runWorker = () => {
    setLoading(true);
    const worker = new Worker(new URL('@/workers/counterWorker.js', import.meta.url), { type:'module' });
    worker.postMessage(1e7); // pass 10 million items to worker


    worker.onmessage = (e) => {
      setResult(e.data);
      setLoading(false);
      worker.terminate();
    };
  };

  return (
    <div>
      <h2>🔁 Heavy Counter (React + Worker)</h2>
      <button onClick={runWorker} disabled={loading}>
        {loading ? 'Calculating...' : 'Run Task'}
      </button>
      {result && <p>Result: {result}</p>}
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

🧩 Using Web Workers in Vue 3

Vue makes this just as easy, especially with Vite.

Using the same worker setup, we can create a vue component that utilizes it:

HeavyCounter.vue

<script setup>
import { ref } from 'vue';

const result = ref(null);
const loading = ref(false);

const runWorker = () => {
  loading.value = true;
      const worker = new Worker(new URL('@/workers/counterWorker.js', import.meta.url), { type:'module' });


  worker.postMessage(1e7);

  worker.onmessage = (e) => {
    result.value = e.data;
    loading.value = false;
    worker.terminate();
  };
};
</script>
<template>
  <div>
    <h2>🔁 Heavy Counter (Vue + Worker)</h2>
    <button @click="runWorker" :disabled="loading">
      {{ loading ? 'Calculating...' : 'Run Task' }}
    </button>
    <p v-if="result !== null">Result: {{ result }}</p>
  </div>
</template>
Enter fullscreen mode Exit fullscreen mode

Communication with the worker is asynchronous, you listen for responses from the worker using worker.onmessage and send data to it using worker.postMessage.
Always remember to call worker.terminate() to stop the worker once it's done to free up resources.

🧰 Bonus: Want more power? Look into:

I really hope you found this article helpful, 🚀 Happy threading!

Top comments (0)