Para melhorar a performance de rolagem/zoom de wheel
, recomendamos que os desenvolvedores
registrem listeners de eventos wheel
e mousewheel
como passivos,
transmitindo a opção {passive: true}
para addEventListener()
. Registrar
os listeners de eventos como passivos informa ao navegador que os listeners wheel não
chamam preventDefault()
e que o navegador pode rolar e
aplicar zoom com segurança sem bloquear os listeners.
O problema é que, na maioria das vezes, os listeners de eventos de roda são conceitualmente passivos (não chame preventDefault()
), mas não são explicitamente especificados dessa forma, exigindo que o navegador aguarde a conclusão do processamento do evento JS antes de começar a rolar/aplicar zoom, mesmo que a espera não seja necessária. No Chrome 56,
corrigimos esse problema no touchstart
e no touchmove
,
e essa mudança foi adotada depois pelo Safari e pelo Firefox. Como é possível notar
no vídeo de demonstração que fizemos naquela época, o comportamento que produzia
um atraso perceptível na resposta de rolagem foi mantido. No Chrome 73, aplicamos
a mesma intervenção aos eventos wheel
e mousewheel
.
A intervenção
Nosso objetivo com essa mudança é reduzir o tempo necessário para atualizar a tela
depois que o usuário começa a rolar pela roda ou pelo touchpad sem que os desenvolvedores precisem
mudar o código. Nossas métricas mostram que 75% dos listeners de eventos
wheel
e mousewheel
registrados em destinos raiz (janela, documento ou corpo) não
especificam valores para a opção passiva, e mais de 98% deles
não chamam preventDefault()
. No Chrome 73, estamos mudando os listeners
wheel
e mousewheel
registrados em destinos raiz (janela,
documento ou corpo) para passivos por padrão. Isso significa que um listener de eventos
como:
window.addEventListener("wheel", func);
se torna equivalente a:
window.addEventListener("wheel", func, {passive: true});
Além disso, chamar preventDefault()
dentro do listener será ignorado com o
seguinte aviso do DevTools:
[Intervention] Unable to preventDefault inside passive event listener due
to target being treated as passive. See https://www.chromestatus.com/features/6662647093133312
Falha e orientação
Na grande maioria dos casos, nenhuma falha será observada. Somente em casos raros
(menos de 0,3% das páginas de acordo com nossas métricas), a rolagem/zoom não intencional
pode acontecer devido à chamada de preventDefault()
ser ignorada dentro dos
listeners, que são tratados como passivos por padrão. O aplicativo pode
determinar se está atingindo esse objetivo, verificando se a chamada de
preventDefault()
teve algum efeito pela propriedade defaultPrevented
. A correção
para os casos afetados é relativamente fácil: transmita {passive: false}
para
addEventListener()
para substituir o comportamento padrão e preservar o listener
de eventos como bloqueio.