Bạn có từng thấy ứng dụng web của mình bị đơ trong vài giây khi xử lý một tác vụ phức tạp—như phân tích một tệp JSON lớn, xử lý số liệu, hoặc thay đổi kích thước hình ảnh?
Đó là lúc main thread (luồng chính) của trình duyệt bị quá tải.
Nhưng đừng lo! Có một "siêu anh hùng" trong thế giới trình duyệt có thể giúp giảm bớt gánh nặng cho luồng chính. Xin giới thiệu Web Workers, những người bạn JavaScript hoạt động nền của bạn.
Trong bài viết này, chúng ta sẽ khám phá cách tích hợp Web Workers vào cả ứng dụng React và Vue. Hãy cùng làm cho ứng dụng của bạn nhanh hơn, mượt mà hơn, và phản hồi tốt hơn—với một chút vui vẻ nữa nhé!
Vì sao nên dùng Web Workers?
JavaScript là ngôn ngữ đơn luồng, nghĩa là main thread của trình duyệt phải xử lý cả giao diện người dùng lẫn logic. Điều này có thể dẫn đến tình trạng quá tải và gây lag, đặc biệt khi thực hiện các thao tác tốn tài nguyên.
Web Workers chạy trên một luồng riêng biệt với luồng chính, cho phép xử lý các tác vụ nặng mà không chặn giao diện người dùng.
Khi nào nên dùng Web Workers
🔁 1. Tính toán nặng
Khi bạn thực hiện các tác vụ mất nhiều thời gian như:
- Xử lý dữ liệu lớn (ví dụ: phân tích tệp CSV, xử lý log)
- Xử lý hình ảnh (ví dụ: bộ lọc, nén ảnh)
- Tính toán mật mã
- Mô phỏng hoặc toán học phức tạp
Những tác vụ này sẽ chặn luồng chính nếu không được chuyển sang Web Worker.
📈 2. Xử lý dữ liệu thời gian thực
Khi bạn cần truyền và xử lý dữ liệu thời gian thực:
- WebSocket streams (bảng giá giao dịch, game nhiều người chơi)
- Phân tích âm thanh/hình ảnh
- Phân tích dữ liệu từ cảm biến IoT
🔍 3. Suy luận Machine Learning trên trình duyệt
Sử dụng mô hình học máy (như TensorFlow.js hoặc ONNX) có thể gây tải nặng lên luồng chính. Thực hiện suy luận trong Web Worker giúp giao diện mượt hơn.
🧠 4. Ứng dụng cần phản hồi cực nhanh
Dành cho các ứng dụng cần giao diện phản hồi gần như tức thì:
- Trình chỉnh sửa đồ họa
- Trình soạn thảo mã
- Công cụ làm việc nhóm thời gian thực
Khi nào không nên dùng Web Workers
🐣 1. Tác vụ nhẹ hoặc ngắn
Không nên dùng Web Worker cho các thao tác đơn giản. Việc khởi tạo Web Worker tốn chi phí, đôi khi còn chậm hơn việc xử lý ngay trên luồng chính.
🔗 2. Khi cần truy cập DOM
Web Worker không thể:
- Đọc/ghi DOM
- Truy cập window, document, hoặc localStorage
- Hãy chỉ dùng cho xử lý dữ liệu, không phải thao tác giao diện.
📦 3. Khi đã có xử lý trên Backend
Nếu tác vụ đã được xử lý bởi backend hoặc API, dùng Web Worker để xử lý lại ở phía client có thể thừa thãi.
🔌 4. Khi hỗ trợ trình duyệt là quan trọng
Web Workers được hỗ trợ rộng rãi, nhưng vẫn có những trường hợp ngoại lệ (ví dụ: trình duyệt rất cũ hoặc webview trên thiết bị nhúng). Cần kiểm tra trước.
Web Worker hoạt động ra sao?
Trước khi dùng framework, hãy hiểu cách Web Worker hoạt động cơ bản.
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);
};
main.js
const worker = new Worker('worker.js'); worker.postMessage(10); worker.onmessage = function (event) { console.log('Result from worker:', event.data); // 20
};
Sử dụng Web Workers trong React
Tích hợp worker vào ứng dụng React (dùng Vite). Tạo một component sử dụng worker để thực hiện tính toán nặng.
Cài đặt
**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);
};
Component React ví dụ
**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> );
}
Sử dụng Web Workers trong Vue 3
Vue cũng rất dễ tích hợp Web Worker, đặc biệt khi dùng Vite.
**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>
Giao tiếp với Web Worker là bất đồng bộ: bạn gửi dữ liệu bằng worker.postMessage
và nhận phản hồi qua worker.onmessage
.
Luôn nhớ gọi worker.terminate()
sau khi worker hoàn thành để giải phóng tài nguyên.
Hy vọng thông tin trong bài viết này sẽ giúp ích phần nào cho các bạn!