Giới thiệu
Trong các ứng dụng web hiện đại, hiệu suất là một yếu tố quan trọng ảnh hưởng trực tiếp đến trải nghiệm người dùng. Một trong những nguyên nhân chính gây ra tình trạng giật lag, hoặc block UI là do các tác vụ tính toán nặng (heavy tasks) được thực thi trực tiếp ngay trên (main thread).
Để giải quyết vấn đề này, JavaScript cung cấp giải pháp Web Workers, cho phép chạy các đoạn mã song song trong một luồng riêng biệt, giúp tránh xử lí trên main thread và tăng hiệu suất ứng dụng.
1. Web Workers là gì?
Web Workers là một API của trình duyệt cho phép bạn thực thi JavaScript trong một luồng riêng biệt với luồng chính của ứng dụng.
- Web Workers có thể giao tiếp với main thread thông qua
postMessage
. - Phù hợp để xử lý: tính toán nặng, phân tích dữ liệu, xử lý ảnh, nén file,...
2. Tại sao nên sử dụng Web Workers?
Lợi ích:
- Không làm block UI: vì tác vụ không chạy trên main thread.
- Cải thiện UX: giao diện vẫn phản hồi trong khi xử lý tác vụ.
- Tăng hiệu suất khi xử lí các tác vụ tính toán phức tạp.
Khi không sử dụng Web Workers:
- UI dễ bị đơ khi xử lý JSON lớn, vòng lặp nhiều, hoặc xử lí thuật toán nặng hoặc xử lí loop đệ quy nhiều vòng.
- User có thể nhầm tưởng ứng dụng bị crash nếu không phản hồi.
3. Ví dụ về cách sử dụng Web Workers cho bài toán tính giai thừa
Giả sử bạn cần thực hiện phép tính giai thừa (n!
) với BigInt – đây là một tác vụ có thể gây chậm hoặc "đơ" giao diện nếu xử lý trực tiếp trong main thread. Ở ví dụ này ta sử dụng Web Worker
để tách hàm xử lí factorial
ra luồng một luồng riêng không liên quan đến main thread
Ví dụ đơn giản gồm:
- Một file Web Worker để tính giai thừa.
- Một component React (TSX) gồm ô input, button nhấn để gửi dữ liệu vào worker file, và các thẻ p để hiển thị kết quả.
🧮 factorialWorker.ts
– File worker
self.onmessage = function (e) { const number = e.data; const result = factorial(number); self.postMessage(result);
}; function factorial(n: number): BigInt { let result = BigInt(1); for (let i = 2; i <= n; i++) { result *= BigInt(i); } return result;
} export {};
🧑💻 FactorialCalculator.tsx
– React component
import React, { useState, useRef } from "react"; const FactorialCalculator: React.FC = () => { const [input, setInput] = useState<number>(100000); const [result, setResult] = useState<number | null>(null); const [loading, setLoading] = useState(false); const [totalTime, setTotalTime] = useState(0); const workerRef = useRef<Worker | null>(null); const handleCalculate = () => { setResult(null); setTotalTime(0); setLoading(true); const startTime = performance.now(); // Start timing const worker = new Worker(new URL("@src/worker/factorialWorker", import.meta.url)); workerRef.current = worker; worker.postMessage(input); worker.onmessage = (e: MessageEvent<number>) => { const endTime = performance.now(); // End timing setTotalTime(endTime - startTime); // Calculate total time in milliseconds setResult(e.data); setLoading(false); worker.terminate(); }; }; return ( <div> <input type="number" value={input} onChange={(e) => setInput(Number(e.target.value))} placeholder="Nhập số nguyên dương" /> <button onClick={handleCalculate} disabled={loading}> {loading ? "Đang tính..." : "Tính giai thừa"} </button> {result !== null && <p>Kết quả: {result}</p>} {totalTime > 0 && <p>Thời gian tính toán: {totalTime.toFixed(3)} ms</p>} </div> );
}; export default FactorialCalculator;
Kết quả:
Khi không sử dụng Web Worker | Khi sử dụng Web Worker |
---|---|
![]() |
![]() |
Ta có thể thấy khi sử dụng web-worker, UI không những không bị block mà còn mượt mà hơn rất nhiều so với khi không sử dụng.
Đơn giản hơn thì ta có thể sử dụng Thư viện https://useworker.js.org/ để code nhanh hơn mà không cần tách hàm như trên
4. Lưu ý khi sử dụng web worker
- Không thể truy cập đến DOM từ trong worker file.
- Đảm bảo luồng giao tiếp
postMessage
rõ ràng và không gây race condition. - Có thể dùng
Comlink
để đơn giản hóa giao tiếp.
5. Khi nào nên dùng Web Workers?
Tình huống | Có nên dùng Worker? |
---|---|
Tính toán nặng như mã hóa, nén file | ✅ Cần |
Xử lý file JSON lớn (>1MB) | ✅ Cần |
Cập nhật UI đơn giản | ❌ Không cần |
Fetch API, gọi server | ❌ Không cần (dùng async/await cho lẹ ![]() |
6. Các option nâng cao khác
- SharedWorker: chia sẻ worker giữa nhiều tab.
- Service Worker: xử lý request, cache – khác với Web Worker.
- OffscreenCanvas: render canvas trong worker (đặc biệt hữu ích với đồ họa).
Kết luận
Web Workers là công cụ mạnh mẽ giúp cải thiện hiệu suất của các ứng dụng web hiện đại. Việc tách biệt các tác vụ nặng ra khỏi luồng chính sẽ giúp UI luôn mượt mà, thân thiện với người dùng. Hãy cân nhắc sử dụng Web Workers khi bắt đầu thấy trình duyệt bị "đơ", "lag" khi chạy những tác vụ phức tạp.
Xem thêm các bài viết tại: vunguyenit.site