Đẩy nhanh con lăn chuột theo mặc định

Sahel Sharify
Sahel Sharify

Để cải thiện hiệu suất cuộn/thu phóng wheel, các nhà phát triển nên đăng ký trình nghe sự kiện wheelmousewheel dưới dạng 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 dưới dạng thụ động cho trình duyệt biết rằng trình nghe con lăn sẽ không gọi preventDefault(), đồng thời trình duyệt có thể thực hiện thao tác cuộn và thu phóng một cách an toàn mà không chặn trình nghe.

Vấn đề là trình nghe sự kiện con lăn thường là trình nghe bị động (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 phải đợi cho việc xử lý sự kiện JS kết thúc trước khi bắt đầu cuộn/thu phóng mặc dù không cần thiết phải chờ. Trong Chrome 56, chúng tôi đã khắc phục vấn đề này cho touchstarttouchmove, sau đó, thay đổi đó đã được cả Safari và Firefox áp dụng. Như bạn có thể thấy từ video minh hoạ mà chúng tôi thực hiện tại thời điểm đó, việc giữ nguyên hành vi đã gây ra độ trễ đáng kể trong phản hồi cuộn. Hiện tại trong Chrome 73, chúng tôi đã áp dụng cùng một biện pháp can thiệp cho các sự kiện wheelmousewheel.

Sự can thiệp

Mục tiêu của chúng tôi đối với 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 wheelmousewheel được đăng ký trên 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 loại này không gọi preventDefault(). Trong Chrome 73, chúng tôi sẽ thay đổi trình nghe wheelmousewheel đã đăng ký trên mục tiêu gốc (cửa sổ, tài liệu hoặc nội dung) 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});

Đồng thời, việc gọi preventDefault() bên trong trình nghe sẽ bị bỏ qua kèm theo cảnh báo sau đây về Công cụ cho nhà phát triển:

[Intervention] Unable to preventDefault inside passive event listener due
to target being treated as passive. See https://www.chromestatus.com/features/6662647093133312

Phân tích số liệu và hướng dẫn

Trong hầu hết các trường hợp, hệ thống sẽ không quan sát 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), thao tá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 các trình nghe bị động theo mặc định. Ứng dụng của bạn có thể xác định xem ứng dụng có gặp trường hợp này hay không bằng cách kiểm tra xem lệnh gọi preventDefault() có ảnh hưởng gì thông qua thuộc tính defaultPrevented hay không. Việc khắc phục 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 ở dạng chặn.