Để cải thiện hiệu suất cuộn/thu phóng wheel
, nhà phát triển nên đăng ký trình nghe sự kiện wheel
và mousewheel
ở chế độ thụ động bằng cách truyền tuỳ chọn {passive: true}
đến addEventListener()
. Việc đăng ký trình nghe sự kiện ở chế độ thụ động sẽ cho trình duyệt biết rằng trình nghe con lăn sẽ không gọi preventDefault()
và trình duyệt có thể cuộn và thu phóng một cách an toàn mà không chặn trình nghe.
Vấn đề là hầu hết trình nghe sự kiện con lăn đều mang tính thụ động về mặt khái niệm (không gọi preventDefault()
) nhưng không được chỉ định rõ ràng như vậy, yêu cầu trình duyệt chờ xử lý sự kiện JS hoàn tất trước khi bắt đầu cuộn/thu phóng mặc dù không cần phải chờ. Trong Chrome 56,
chúng tôi đã khắc phục vấn đề này cho touchstart
và touchmove
,
và thay đổi đó sau đó đã được cả Safari và Firefox áp dụng. Như bạn có thể thấy trong video minh hoạ mà chúng tôi đã tạo tại thời điểm đó, việc để nguyên hành vi này đã gây ra độ trễ đáng kể trong phản hồi cuộn. Giờ đây, trong Chrome 73, chúng tôi đã áp dụng biện pháp can thiệp tương tự cho các sự kiện wheel
và mousewheel
.
Can thiệp
Mục tiêu của chúng tôi khi thực hiện thay đổi này là giảm thời gian cập nhật màn hình sau khi người dùng bắt đầu cuộn bằng con lăn hoặc bàn di chuột mà không cần nhà phát triển thay đổi mã. Các chỉ số của chúng tôi cho thấy 75% trình nghe sự kiện wheel
và mousewheel
được đăng ký trên các mục tiêu gốc (cửa sổ, tài liệu hoặc nội dung) không chỉ định giá trị nào cho tuỳ chọn thụ động và hơn 98% trình nghe như vậy không gọi preventDefault()
. Trong Chrome 73, chúng tôi sẽ thay đổi trình nghe wheel
và mousewheel
được đăng ký trên các mục tiêu gốc (cửa sổ, tài liệu hoặc phần thân) thành thụ động theo mặc định. Điều này có nghĩa là trình nghe sự kiện như:
window.addEventListener("wheel", func);
sẽ tương đương với:
window.addEventListener("wheel", func, {passive: true});
Và lệnh gọi preventDefault()
bên trong trình nghe sẽ bị bỏ qua kèm theo cảnh báo sau trong DevTools:
[Intervention] Unable to preventDefault inside passive event listener due
to target being treated as passive. See https://www.chromestatus.com/features/6662647093133312
Hư hỏng và hướng dẫn
Trong hầu hết các trường hợp, bạn sẽ không thấy sự cố nào. Chỉ trong một số ít trường hợp (dưới 0,3% số trang theo chỉ số của chúng tôi), việc cuộn/thu phóng ngoài ý muốn có thể xảy ra do lệnh gọi preventDefault()
bị bỏ qua bên trong trình nghe được coi là thụ động theo mặc định. Ứng dụng của bạn có thể xác định xem ứng dụng có thể gặp phải lỗi này trong thực tế hay không bằng cách kiểm tra xem việc gọi preventDefault()
có ảnh hưởng gì thông qua thuộc tính defaultPrevented
hay không. Cách khắc phục cho các trường hợp bị ảnh hưởng tương đối dễ dàng: truyền {passive: false}
đến addEventListener()
để ghi đè hành vi mặc định và giữ nguyên trình nghe sự kiện ở chế độ chặn.