- Trong JavaScript,
setTimeout(0) thực tế thường không chạy ngay lập tức mà bị trễ tối thiểu 4ms, đây là giới hạn mặc định của trình duyệt để ngăn lạm dụng
- Ràng buộc này nhằm ngăn website lạm dụng bộ hẹn giờ một cách bừa bãi gây hao pin hoặc làm giảm khả năng tương tác, và trong chế độ pin hay ở tab nền, giới hạn còn có thể bị siết mạnh hơn như 16ms hoặc 1 giây
- Các nhà phát triển đã sử dụng nhiều API hẹn giờ thay thế như
setImmediate, MessageChannel.postMessage, window.postMessage, scheduler.postTask để vượt qua giới hạn của setTimeout
- Kết quả benchmark thực tế cho thấy Chrome và Firefox áp dụng mức chặn 4ms, nhưng
MessageChannel và scheduler.postTask hoạt động gần như không có độ trễ, còn Safari có xu hướng hạn chế setTimeout mạnh hơn
- Về bản chất, đây là vấn đề cân bằng giữa bảo vệ trải nghiệm người dùng và quyền tự do của nhà phát triển; hiện tại Scheduler API đang trở thành lời giải được chuẩn hóa, nhưng nếu xảy ra lạm dụng thì cũng có thể sẽ xuất hiện can thiệp của trình duyệt (Intervention) mới
Bối cảnh của giới hạn setTimeout
Sự xuất hiện của các API hẹn giờ khác
setImmediate: chỉ được hỗ trợ trên IE và Edge cũ, nay gần như đã biến mất
MessageChannel.postMessage: chuyển công việc vào event loop qua một kênh riêng
window.postMessage: hiệu năng tốt nhưng có nguy cơ xung đột với script khác
scheduler.postTask: được hỗ trợ trên trình duyệt hiện đại và được đánh giá là lựa chọn ổn định nhất
Kết quả benchmark (MacBook Pro 2021, đo lặp 101 lần)
- Chrome 139:
setTimeout 4.2ms, scheduler.postTask 0ms
- Firefox 142:
setTimeout 4.72ms, scheduler.postTask 0.01ms
- Safari 18.4:
setTimeout 26.73ms, MessageChannel 0.52ms, window.postMessage 0.05ms
Trường hợp của fake-indexeddb
- IndexedDB muốn transaction được tự động commit ngay sau khi microtask của event loop kết thúc
setImmediate của Node.js là lý tưởng, nhưng trên trình duyệt thì setTimeout lại kém hiệu quả
- Trên Chrome, một tác vụ mất 300ms có thể kéo dài tới 4.8 giây trên trình duyệt
- Cách giải quyết là dùng mặc định
scheduler.postTask, và dùng MessageChannel/window.postMessage làm phương án dự phòng để đảm bảo tương thích
Tranh luận về can thiệp của trình duyệt
- Một phía cho rằng cần giới hạn timer để nhà phát triển được bảo vệ khỏi chính mình
- Phía còn lại cho rằng cần đảm bảo tự do để nhà phát triển tự đo đạc và tối ưu
- Cuối cùng, theo nguyên tắc ưu tiên người dùng, trình duyệt vẫn can thiệp (intervention) để ngăn lạm dụng
- Scheduler API là sự thỏa hiệp giữa hai lập trường, được thiết kế để trao cho nhà phát triển quyền kiểm soát tác vụ chi tiết hơn đồng thời phù hợp với pipeline render của trình duyệt
Triển vọng sắp tới
postTask và postMessage có vẻ sẽ tiếp tục không bị throttle trong một thời gian
- Nhưng nếu các mức ưu tiên cao như
user-blocking bị lạm dụng thì vẫn có thể lại xuất hiện can thiệp
- Về dài hạn, thậm chí có thể sẽ cần một API thay thế khác như
scheduler2
Chưa có bình luận nào.