+1

Tăng tốc ứng dụng Web của bạn với Web Workers trong React và Vue

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!


All Rights Reserved

Viblo
Let's register a Viblo Account to get more interesting posts.