Делаем прокрутку колеса быстрой по умолчанию

Сахель Шарифи
Sahel Sharify

Чтобы улучшить производительность прокрутки/масштабирования wheel , разработчикам рекомендуется зарегистрировать прослушиватели событий wheel и mousewheel как пассивные, передав параметр {passive: true} в addEventListener() . Регистрация прослушивателей событий в качестве пассивных сообщает браузеру, что прослушиватели колеса не будут вызывать preventDefault() , и браузер может безопасно выполнять прокрутку и масштабирование, не блокируя прослушиватели.

Проблема заключается в том, что чаще всего прослушиватели событий колеса концептуально пассивны (не вызывают preventDefault() ), но не указаны явно как таковые, требуя, чтобы браузер ждал завершения обработки событий JS, прежде чем он начнет прокручивать/масштабировать, даже если ожидает не обязательно. В Chrome 56 мы исправили эту проблему для touchstart и touchmove , и позже это изменение было принято как в Safari, так и в Firefox. Как вы можете видеть из демонстрационного видео, которое мы сделали в то время, оставив поведение таким, какое оно было, возникла заметная задержка реакции на прокрутку. Теперь, в Chrome 73, мы применили такое же вмешательство к событиям wheel и mousewheel .

Вмешательство

Наша цель с этим изменением — сократить время, необходимое для обновления дисплея после того, как пользователь начинает прокрутку с помощью колесика или сенсорной панели, без необходимости разработчикам менять код. Наши метрики показывают, что 75 % прослушивателей событий wheel и mousewheel , зарегистрированных в корневых целевых объектах (окне, документе или теле), не указывают никаких значений для пассивной опции и более 98 % таких прослушивателей не вызывают preventDefault() . В Chrome 73 мы меняем прослушиватели wheel и mousewheel , зарегистрированные на корневых объектах (окне, документе или теле), на пассивные по умолчанию. Это означает, что прослушиватель событий типа:

window.addEventListener("wheel", func);

становится эквивалентным:

window.addEventListener("wheel", func, {passive: true});

А вызов метода preventDefault() внутри прослушивателя будет проигнорирован со следующим предупреждением DevTools:

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

Поломка и руководство

В подавляющем большинстве случаев поломок не будет. Только в редких случаях (менее 0,3% страниц по нашим показателям) может произойти непреднамеренная прокрутка/масштабирование из-за того, что вызов preventDefault() игнорируется внутри слушателей, которые по умолчанию считаются пассивными. Ваше приложение может определить, может ли оно сталкиваться с этим в реальных условиях, проверив, оказал ли вызов preventDefault() какой-либо эффект через свойство defaultPrevented . Исправить затронутые случаи относительно просто: передайте {passive: false} в addEventListener() , чтобы переопределить поведение по умолчанию и сохранить прослушиватель событий как блокирующий.