Long Tasks
Các tác vụ JavaScript chạy liên tục trên main thread hơn 50ms, gây trì hoãn phản hồi người dùng và ảnh hưởng FID/INP.
Long Tasks là gì?
Long Tasks (tác vụ dài) là những đoạn mã JavaScript chạy liên tục trên main thread trong hơn 50 mili giây. Khi xảy ra, chúng chặn luồng xử lý chính của trình duyệt — khiến trang không thể phản hồi thao tác người dùng như nhấn nút, cuộn hay nhập liệu trong suốt thời gian đó.
Đây không phải lỗi lập trình mà là hiện tượng hiệu năng hệ thống: một tác vụ duy nhất chiếm dụng CPU quá lâu, làm gián đoạn chu kỳ render và event loop. Theo tiêu chuẩn Web Vitals của Google, Long Tasks trực tiếp ảnh hưởng đến chỉ số First Input Delay (FID) và Interaction to Next Paint (INP) — hai trong ba chỉ số cốt lõi đánh giá trải nghiệm người dùng.
Tại sao quan trọng trong SEO?
Google đã xác nhận rõ ràng rằng trải nghiệm người dùng là yếu tố xếp hạng trực tiếp. Từ năm 2021, Core Web Vitals (bao gồm FID/INP) được tích hợp vào thuật toán tìm kiếm trên thiết bị di động và máy tính. Một trang có nhiều Long Tasks thường:
- Có tỷ lệ thoát cao hơn do phản hồi chậm;
- Mất điểm trong báo cáo PageSpeed Insights và Lighthouse;
- Gặp rủi ro bị giảm hiển thị ở vị trí cao trên kết quả tìm kiếm — đặc biệt với truy vấn mang tính hành động (ví dụ: "đặt hàng", "đăng ký ngay").
Theo dữ liệu thực tế từ HTTP Archive (tháng 6/2024), khoảng 37% trang web top 10 triệu có ít nhất một Long Task trong lần tải đầu tiên trên thiết bị di động. Trong nhóm trang có INP > 200ms, hơn 68% có ít nhất 3 Long Tasks kéo dài trên 100ms.
Cách hoạt động
Trình duyệt xử lý mọi thứ trên một luồng chính (main thread): từ phân tích HTML/CSS, chạy JavaScript, đến vẽ pixel lên màn hình. Khi JavaScript thực thi, nó chiếm toàn bộ main thread — không có cơ chế “ngắt giữa chừng” trừ khi mã chủ động nhường quyền.
Một Long Task xuất hiện khi:
- Mã JavaScript thực thi liên tục (không gọi
await,setTimeout,requestIdleCallbackhoặcpostMessage); - Thời gian thực thi vượt ngưỡng 50ms — đây là ngưỡng do trình duyệt đặt ra để đảm bảo khả năng phản hồi trong vòng 100ms (theo nguyên tắc RAIL);
- Trình duyệt không thể xử lý input từ người dùng trong suốt khoảng thời gian đó.
Lưu ý: Không phải tất cả mã chạy >50ms đều gây hại — nếu diễn ra khi người dùng không tương tác (ví dụ: xử lý nền sau khi trang đã hiển thị), tác động đến FID/INP là thấp. Nhưng nếu xảy ra ngay sau khi người dùng nhấn nút, hậu quả rất nghiêm trọng.
Hướng dẫn thực hiện
Dưới đây là quy trình kiểm tra và tối ưu Long Tasks theo thứ tự ưu tiên:
- Phát hiện: Dùng Chrome DevTools → tab Performance → ghi lại tương tác (ví dụ: nhấn nút), rồi lọc theo “Long Tasks” trong bảng timeline. Hoặc chạy Lighthouse với tùy chọn “Performance” bật.
- Phân tích nguồn gốc: Nhấp vào từng Long Task để xem call stack — xác định hàm nào chiếm nhiều thời gian nhất (ví dụ:
JSON.parse()với dữ liệu lớn, vòng lặpforkhông giới hạn, hoặc xử lý DOM hàng loạt). - Tối ưu theo nhóm:
- Chia nhỏ tác vụ: Dùng
setTimeout(fn, 0),queueMicrotask()hoặcrequestIdleCallback()để chia logic thành các phần nhỏ hơn 50ms. - Di chuyển ra ngoài main thread: Chuyển xử lý nặng sang Web Worker (ví dụ: phân tích dữ liệu, mã hóa, tính toán).
- Loại bỏ hoặc trì hoãn: Gỡ bỏ mã khởi tạo không cần thiết lúc tải (ví dụ: analytics thừa, widget không hiển thị), hoặc tải sau khi trang ổn định (
document.readyState === 'complete').
- Chia nhỏ tác vụ: Dùng
- Kiểm thử lại: Đo INP trước/sau bằng công cụ WebPageTest hoặc Chrome User Experience Report (CrUX) để xác minh cải thiện.
Lỗi thường gặp
Dưới đây là những sai lầm phổ biến khi xử lý Long Tasks và cách khắc phục:
| Lỗi | Hệ quả | Cách khắc phục |
|---|---|---|
Dùng for lặp 10.000+ phần tử đồng bộ |
Tạo Long Task duy nhất >200ms | Chia thành từng khối 50 phần tử, dùng requestIdleCallback hoặc setTimeout giữa các khối |
Gọi innerHTML với chuỗi HTML lớn |
Phân tích + render DOM chậm, dễ vượt 50ms | Dùng document.createDocumentFragment() hoặc thư viện virtual DOM; tránh cập nhật DOM trong vòng lặp |
| Chạy mã phân tích (analytics) ngay khi tải trang | Chiếm main thread khi người dùng đang tương tác | Trì hoãn 500–1000ms sau load event, hoặc chỉ chạy khi người dùng không tương tác 5s |
Ví dụ thực tế
Một website thương mại điện tử phát hiện INP = 320ms trên trang sản phẩm. Kiểm tra trong DevTools cho thấy có 4 Long Tasks khi người dùng nhấn nút "Thêm vào giỏ" — nguyên nhân là hàm updateCartUI() đồng thời:
- Phân tích lại toàn bộ giỏ hàng từ localStorage (dữ liệu ~2MB JSON);
- Cập nhật 12 thẻ DOM bằng
innerHTML; - Gửi yêu cầu analytics đồng bộ.
Sau tối ưu:
- Chuyển phân tích JSON sang Web Worker;
- Dùng
textContentvàclassListthay vìinnerHTML; - Gửi analytics qua
navigator.sendBeacon()và trì hoãn 800ms.
Câu hỏi thường gặp
Long Tasks có giống với “blocking scripts” không?
Không hoàn toàn. Blocking scripts (script chặn render) là file <script> chưa tải xong khiến trình duyệt tạm dừng phân tích HTML. Long Tasks là mã đã chạy nhưng chiếm main thread quá lâu. Một script có thể không blocking nhưng vẫn tạo Long Task nếu logic bên trong nặng.
Ngưỡng 50ms có thay đổi không?
Không — 50ms là ngưỡng cố định do W3C và các trình duyệt quy định trong tiêu chuẩn Long Tasks API. Tuy nhiên, mức độ ảnh hưởng đến INP phụ thuộc vào thời điểm xảy ra: nếu xảy ra khi người dùng đang tương tác, ngay cả 51ms cũng được tính. Nếu xảy ra khi trình duyệt đang nghỉ, nó không góp vào INP.
Có nên loại bỏ hoàn toàn Long Tasks?
Không cần và cũng không khả thi. Mục tiêu là giảm thiểu số lượng và thời lượng — đặc biệt trong các khoảnh khắc tương tác. Một trang web tốt thường có ≤1 Long Task dưới 100ms trong lần tải đầu tiên, và không có Long Task nào trong 500ms sau thao tác người dùng. Việc loại bỏ hoàn toàn là không thực tế với ứng dụng phức tạp.