Heavy computations on the main thread can lead to sluggish UI, dropped frames, and poor user experience. Fortunately, Web Workers allow us to offload intensive tasks to background threads.
In this article, we'll explore how to use Web Workers in a Vue 3 project to keep the UI responsive while running CPU-heavy tasks.
Enjoy!
🤔 Why Use Web Workers in Vue?
JavaScript is single-threaded, which means the main thread handles both UI rendering and logic execution. When you perform complex operations (e.g., image processing, data crunching, cryptography), it can block the main thread.
Source: https://web.dev/articles/workers-overview
Web Workers help by running such tasks in a separate thread that comes with benefits such as; keeping UI smooth and responsive, avoiding "frozen" interactions, and improving perceived performance.
When working with Web Workers, there are few best practices that we should follow:
- Offload only CPU-intensive work: Don’t use workers for simple logic.
- Terminate the worker after use: Prevent memory leaks.
- Use transferable objects: For large binary data (ArrayBuffer), use transferables to avoid copying overhead.
-
Consider
comlink
: A small library that simplifies worker communication.
Remember that workers don’t have access to the DOM so if your heavy operation requires access to it, you should not use a web worker for that.
🟢 Creating a Web Worker in Vue 3
To use Web Workers, we will need to create a separate JavaScript file that the worker will run:
// src/workers/heavyTaskWorker.js
self.onmessage = function (e) {
const input = e.data;
// Example heavy computation: Fibonacci
function fibonacci(n) {
if (n <= 1) return n;
return fibonacci(n - 1) + fibonacci(n - 2);
}
const result = fibonacci(input);
self.postMessage(result);
};
Next, we would need to use the Worker in a Vue Component:
<script setup>
import { ref } from 'vue';
const number = ref(35);
const result = ref(null);
const loading = ref(false);
const runWorker = () => {
loading.value = true;
const worker = new Worker(new URL('@/workers/heavyTaskWorker.js', import.meta.url), {
type: 'module'
});
worker.postMessage(number.value);
worker.onmessage = (e) => {
result.value = e.data;
loading.value = false;
worker.terminate();
};
};
</script>
<template>
<div>
<label>Enter a number: </label>
<input v-model.number="number" type="number" />
<button @click="runWorker">Run Fibonacci</button>
<div v-if="loading">Computing...</div>
<div v-else-if="result !== null">Result: {{ result }}</div>
</div>
</template>
When using Vite, workers can be loaded with new URL()
syntax. Webpack and other bundlers may require different configuration.
Communication with a Web Worker is asynchronous and message-based:
-
worker.postMessage(data)
sends data to the worker. -
worker.onmessage = (e) => {}
receives data back from the worker. -
worker.terminate()
stops the worker once it's done.
You can also handle errors with worker.onerror
.
📖 Learn more
If you would like to learn more about Vue, Nuxt, JavaScript or other useful technologies, checkout VueSchool by clicking this link or by clicking the image below:
It covers most important concepts while building modern Vue or Nuxt applications that can help you in your daily work or side projects 😉
✅ Summary
Integrating Web Workers in Vue 3 helps manage performance bottlenecks caused by heavy computations. By offloading work to a background thread, you keep the UI fast and fluid, especially in data-intensive apps.
Take care and see you next time!
And happy coding as always 🖥️
Top comments (1)
Could you please add any real time scenario examples. It would be really helpful