Long task là bất kỳ công việc nào chiếm main thread quá 50ms. Trong khoảng đó browser không xử lý được thao tác người dùng, không vẽ lại được — giao diện đứng.
Ngưỡng 50ms không tuỳ tiện: nó đến từ mô hình RAIL, để mọi phản hồi tương tác vẫn nằm trong 100ms mà người dùng cảm nhận là "ngay lập tức".
Long task ảnh hưởng trực tiếp tới INP (Interaction to Next Paint) — chỉ số Core Web Vitals thay thế FID từ 2024.
// SAI: 10.000 phần tử xử lý một lượt → main thread bị chiếm hàng trăm ms
items.forEach(process)
// ĐÚNG: cắt nhỏ và nhường lượt
async function run(items) {
for (let i = 0; i < items.length; i++) {
process(items[i])
if (i % 100 === 0) await scheduler.yield() // Chrome/Edge 129+, Firefox 142+ — Safari chưa có
}
}Bốn hướng xử lý:
1. Cắt nhỏ + nhường lượt — scheduler.yield(), hoặc setTimeout(0) ở trình duyệt chưa hỗ trợ.
2. Web Worker cho tính toán nặng thật sự (parse file lớn, xử lý ảnh, mã hoá).
3. requestIdleCallback cho việc không gấp.
4. Giảm khối lượng: dùng virtual list cho danh sách dài, chia nhỏ bundle, hoãn code chưa cần.
Cách đo: tab Performance của Chrome DevTools đánh dấu cờ đỏ ở mọi task quá 50ms; PerformanceObserver với entryType: 'longtask' cho phép ghi nhận trên người dùng thật.
Lưu ý: nhược điểm của việc dùng setTimeout(fn, 0) để cắt task là phần việc còn lại xếp sau mọi macrotask khác, kể cả các sự kiện không liên quan — đó chính là lý do scheduler.yield() ra đời.