Technical SEO

Web Workers

Cơ chế chạy script nền độc lập với luồng chính, giúp tránh chặn render và cải thiện hiệu suất trang web.

3 lượt xem Cập nhật: 27/05/2026

Web Workers là gì?

Web Workers là cơ chế trong trình duyệt cho phép chạy các đoạn mã JavaScript trên luồng nền (background thread), tách biệt hoàn toàn với luồng chính xử lý giao diện người dùng (UI thread). Nhờ đó, các tác vụ nặng như tính toán phức tạp, xử lý dữ liệu lớn hoặc gọi API kéo dài không làm chậm hoặc đóng băng giao diện — điều mà trình duyệt thường cảnh báo là "trang không phản hồi".

Web Workers không truy cập được vào DOM, window, document hay các đối tượng phụ thuộc luồng chính. Chúng chỉ làm việc với dữ liệu qua cơ chế gửi/nhận tin nhắn (postMessage và sự kiện message), đảm bảo an toàn và ổn định hệ thống.

Tại sao quan trọng trong SEO?

Web Workers ảnh hưởng gián tiếp nhưng rõ rệt đến các yếu tố xếp hạng SEO hiện đại, đặc biệt là Core Web Vitals:

  • LCP (Largest Contentful Paint): Giảm tải cho luồng chính giúp trình duyệt render nội dung chính nhanh hơn, tránh trì hoãn do script chặn.
  • FID (First Input Delay): Khi luồng chính không bị chiếm dụng bởi tác vụ nặng, người dùng tương tác mượt ngay từ lần nhấn đầu tiên — FID thấp hơn, trải nghiệm tốt hơn.
  • CLS (Cumulative Layout Shift): Tránh thay đổi bố cục bất ngờ do script can thiệp DOM muộn — vì Web Workers không thao tác DOM trực tiếp, nên loại bỏ rủi ro này ở tầng xử lý nền.

Google xác nhận rằng hiệu suất người dùng là tín hiệu xếp hạng chính thức. Một trang có FID dưới 100ms và LCP dưới 2,5s có tỷ lệ giữ chân cao hơn 37% so với trang chậm (theo dữ liệu nghiên cứu của Google năm 2023). Web Workers hỗ trợ đạt các ngưỡng này một cách bền vững — đặc biệt trên thiết bị giá rẻ hoặc mạng chậm.

Cách hoạt động

Mỗi Web Worker chạy trong một môi trường JavaScript riêng, có global scope riêng (self thay vì window), không chia sẻ bộ nhớ với luồng chính. Giao tiếp duy nhất giữa hai bên là qua tin nhắn — dạng chuỗi hoặc đối tượng có thể tuần tự hóa (serializable).

Không có cơ chế đồng bộ (không dùng await hay return trực tiếp). Mọi kết quả đều phải gửi lại bằng postMessage(). Các Worker cũng không kế thừa cookie, header hoặc context xác thực từ trang chủ — trừ khi chủ động truyền qua tin nhắn.

Hướng dẫn thực hiện

  1. Tạo file Worker riêng: Lưu mã xử lý nền vào file JS độc lập (ví dụ: analytics-worker.js). Không đặt logic trong <script> nội tuyến.
  2. Khai báo và khởi tạo: Dùng new Worker('analytics-worker.js') trong script chính. Kiểm tra hỗ trợ trình duyệt trước khi khởi tạo.
  3. Gửi dữ liệu: Dùng worker.postMessage(data), với data là object, số, chuỗi hoặc mảng — không được chứa hàm, DOM node hay vòng lặp tham chiếu.
  4. Nhận phản hồi: Đăng ký sự kiện worker.onmessage = (e) => { console.log(e.data); }.
  5. Dọn dẹp: Gọi worker.terminate() khi không còn cần — tránh rò rỉ bộ nhớ, đặc biệt trên trang SPA.

Lưu ý: Worker không chạy được trên file local (file://) — bắt buộc phải qua server (http/https). Trên localhost, dùng http-server, Live Server hoặc môi trường phát triển tích hợp.

Lỗi thường gặp

  • Lỗi "Uncaught DOMException: Failed to construct 'Worker'": Thường do đường dẫn sai, file không tồn tại, hoặc vi phạm CSP (Content-Security-Policy) — kiểm tra header worker-src hoặc dùng 'self' nếu cho phép.
  • Worker không nhận tin nhắn: Thiếu self.onmessage = ... bên trong file Worker, hoặc gửi dữ liệu không serializable (ví dụ: hàm, Date object chưa chuyển thành chuỗi).
  • Báo lỗi CORS khi load Worker từ domain khác: Web Worker không hỗ trợ cross-origin — bắt buộc cùng origin hoặc dùng blob URL nếu cần linh hoạt hơn (tùy trường hợp).
  • Hiệu suất không cải thiện dù đã dùng Worker: Có thể do gửi quá nhiều tin nhắn nhỏ (overhead network giữa thread), hoặc xử lý trong Worker vẫn phụ thuộc vào I/O chậm (ví dụ: fetch không được await đúng cách). Giải pháp: gộp dữ liệu, dùng Transferable Objects (như ArrayBuffer) để truyền nhanh hơn.

Ví dụ thực tế

Một trang thương mại điện tử cần phân tích hành vi người dùng thời gian thực (scroll depth, click heatmap, thời gian xem sản phẩm) mà không làm chậm tải trang. Thay vì chạy tất cả trong luồng chính:

Trước: Đoạn mã theo dõi chạy đồng bộ → tăng thời gian thực thi luồng chính → FID tăng 180ms (trên Android低端)

Sau khi áp dụng Web Worker:

Chỉ số Trước dùng Worker Sau dùng Worker Thay đổi
FID (ms) 210 65 ↓ 69%
LCP (s) 3.4 2.1 ↓ 38%
Tỷ lệ thoát (mobile) 58% 41% ↓ 29%

Worker chỉ thu thập và gửi batch dữ liệu mỗi 5 giây — giảm số lần gọi mạng và đảm bảo luồng chính luôn sẵn sàng phục vụ người dùng.

Câu hỏi thường gặp

Web Worker có hỗ trợ trên mọi trình duyệt không?

Hỗ trợ trên tất cả trình duyệt hiện đại (Chrome, Firefox, Safari 16.4+, Edge từ phiên bản 79). Safari hỗ trợ đầy đủ kể từ iOS 16.4 và macOS Ventura 13.3 — trước đó thiếu một số tính năng như SharedWorker hoặc AudioWorklet. Kiểm tra bằng typeof Worker !== 'undefined'.

Có thể dùng Web Worker để tối ưu SEO trực tiếp không?

Không. Web Worker không tạo nội dung HTML, không ảnh hưởng đến khả năng thu thập (crawling) của bot — Googlebot không chạy JavaScript nền và không thực thi Worker. Tác động chỉ gián tiếp qua hiệu suất người dùng và Core Web Vitals, vốn là yếu tố xếp hạng.

Web Worker có tiêu tốn nhiều tài nguyên máy khách không?

Mỗi Worker chiếm bộ nhớ riêng (khoảng 4–6 MB ban đầu), nhưng không gây tải CPU nếu không thực thi. Trình duyệt tự động tạm dừng Worker khi tab bị ẩn (visibilityState = hidden), nên mức tiêu thụ pin và CPU rất thấp. Việc mở quá nhiều Worker đồng thời (trên 10) có thể gây cạnh tranh tài nguyên — khuyến nghị giới hạn 1–3 Worker cho mỗi trang, tùy nhu cầu.