Análise detalhada de um navegador da Web moderno (parte 4)

Mariko Kosaka

A entrada é enviada para o compositor

Esta é a última da série de blogs em quatro partes sobre o Chrome. investigando como lida com nosso código para exibir um site. Na postagem anterior, analisamos o processo de renderização e aprendemos sobre o compositor. Nesta postagem, vamos falar sobre confira como o compositor está permitindo uma interação suave quando a entrada do usuário é recebida.

Eventos de entrada do ponto de vista do navegador

Quando você ouvir "eventos de entrada" você pode pensar apenas em digitar na caixa de texto ou no clique do mouse, mas a do ponto de vista do navegador, uma entrada significa qualquer gesto do usuário. A rolagem da roda do mouse é uma entrada e tocar ou passar o mouse também é um evento de entrada.

Quando ocorre um gesto do usuário, como toque, em uma tela, o processo do navegador é aquele que recebe a gesto no início. No entanto, o processo do navegador só sabe onde o gesto ocorreu, uma vez que o conteúdo de uma guia é processado pelo processo de renderização. Assim, o processo do navegador envia o evento (como touchstart) e suas coordenadas para o processo do renderizador. O processo do renderizador lida com evento adequadamente, localizando o destino do evento e executando os listeners do evento anexados.

evento de entrada
Figura 1: evento de entrada roteado pelo processo do navegador para o processo do renderizador

O criador recebe eventos de entrada

Figura 2: janela de visualização passando o cursor sobre as camadas da página

Na postagem anterior, vimos como o compositor poderia processar a rolagem suavemente compondo camadas rasterizadas. Se nenhum listener de eventos de entrada estiver anexado à página, a linha de execução do criador poderá criar um novo frame composto que seja completamente independente da linha de execução principal. Mas e se algum evento ouvintes foram anexados à página? Como o thread do compositor descobriria se o evento precisa que precisa ser tratada?

Noções básicas sobre regiões roláveis não rápidas

Como a execução do JavaScript é a tarefa da linha de execução principal, quando uma página é composta, a linha de execução do compositor marca uma região da página que tem manipuladores de eventos anexados como "Região rolável não rápida". De Com essas informações, o thread do compositor pode enviar um evento de entrada para a linha de execução principal. se o evento ocorrer naquela região. Se o evento de entrada vier de fora dessa região, o A linha de execução do compositor continua a compor um novo frame sem esperar pela linha de execução principal.

região limitada e não rolável rápida
Figura 3: diagrama da entrada descrita para a região de rolagem não rápida

Esteja ciente ao escrever manipuladores de eventos

Um padrão de manipulação de eventos comum no desenvolvimento da Web é a delegação de eventos. Como os eventos são formados no balão, pode anexar um manipulador de eventos ao elemento superior e delegar tarefas com base no destino do evento. Você deve ter visto ou escrito um código como o abaixo.

document.body.addEventListener('touchstart', event => {
    if (event.target === area) {
        event.preventDefault();
    }
});

Como você só precisa escrever um manipulador de eventos para todos os elementos, a ergonomia desse evento de delegação são atraentes. No entanto, se você analisar esse código do ponto de vista do navegador será exibida, e a página inteira será marcada como uma região de rolagem não rápida. Isso significa que mesmo se aplicativo não se importa com a entrada de determinadas partes da página, o thread compositor precisa se comunicar com a linha de execução principal e aguardar por ela sempre que ocorrer um evento de entrada. Assim, o a capacidade de rolagem suave do compositor é invalidada.

região inteira de página inteira sem rolagem rápida
Figura 4: diagrama da entrada descrita para a região de rolagem não rápida abrangendo uma página inteira

Para evitar que isso aconteça, transmita opções de passive: true no seu evento. ouvinte. Isso indica ao navegador que você ainda quer ouvir o evento na linha de execução principal. mas o compositor pode continuar e compor um novo frame também.

document.body.addEventListener('touchstart', event => {
    if (event.target === area) {
        event.preventDefault()
    }
 }, {passive: true});

Verificar se o evento pode ser cancelado

rolagem da página
Figura 5: uma página da Web com parte da página fixada na rolagem horizontal

Imagine que você tem uma caixa em uma página e quer limitar a direção de rolagem à rolagem horizontal.

Usar a opção passive: true no evento de ponteiro significa que a rolagem da página pode ser suave, mas a rolagem vertical pode ter sido iniciada no momento em que você quer preventDefault para limitar direção de rolagem. Para conferir isso, use o método event.cancelable.

document.body.addEventListener('pointermove', event => {
    if (event.cancelable) {
        event.preventDefault(); // block the native scroll
        /*
        *  do what you want the application to do here
        */
    }
}, {passive: true});

Como alternativa, você pode usar uma regra CSS como touch-action para eliminar completamente o manipulador de eventos.

#area {
  touch-action: pan-x;
}

Encontrar o destino do evento

teste de hit
Figura 6: a linha de execução principal olhando para os registros de pintura perguntando o que está desenhado no ponto x.y.

Quando a linha de execução do compositor envia um evento de entrada para a linha de execução principal, a primeira coisa a ser executada é um hit. para encontrar o destino do evento. O teste de hit usa dados de registros de pintura gerados na renderização para descobrir o que está abaixo das coordenadas de ponto em que o evento ocorreu.

Minimizar despachos de eventos para a linha de execução principal

Na postagem anterior, discutimos como nossa tela típica atualiza a tela 60 vezes por segundo e como precisamos manter o ritmo para uma animação suave. Para entrada, uma tela sensível ao toque típica dispositivo fornece eventos de toque de 60 a 120 vezes por segundo e um mouse típico entrega eventos 100 vezes segundo. O evento de entrada tem maior fidelidade do que a tela pode atualizar.

Se um evento contínuo como touchmove foi enviado para a linha de execução principal 120 vezes por segundo, ele pode acionar uma quantidade excessiva de testes de hit e execução de JavaScript em comparação com a lentidão pode ser atualizada.

eventos não filtrados
Figura 7: eventos que inundam a linha do tempo do frame, causando instabilidade de página

Para minimizar o excesso de chamadas à linha de execução principal, o Chrome une eventos contínuos (como wheel, mousewheel, mousemove, pointermove, touchmove) e atrasa o envio até logo antes da próxima requestAnimationFrame.

eventos agrupados
Figura 8: mesma linha do tempo de antes, mas eventos sendo agrupados e atrasados

Qualquer evento distinto, como keydown, keyup, mouseup, mousedown, touchstart e touchend são enviados imediatamente.

Usar getCoalescedEvents para receber eventos nos frames

Para a maioria dos aplicativos da Web, os eventos reunidos devem ser suficientes para fornecer uma boa experiência do usuário. No entanto, se você estiver criando coisas como desenhar um aplicativo e colocar um caminho baseado touchmove, talvez você perca algumas coordenadas entre elas para desenhar uma linha suave. Nesse caso, você pode usar o método getCoalescedEvents no evento de ponteiro para acessar informações sobre esses eventos agrupados.

getCoalescedEvents
Figura 9: caminho de gesto de toque suave à esquerda, caminho limitado agrupado à direita
window.addEventListener('pointermove', event => {
    const events = event.getCoalescedEvents();
    for (let event of events) {
        const x = event.pageX;
        const y = event.pageY;
        // draw a line using x and y coordinates.
    }
});

Próximas etapas

Nesta série, abordamos o funcionamento interno de um navegador da Web. Se você nunca pensou sobre por que O DevTools recomenda adicionar {passive: true} no seu manipulador de eventos ou por que você pode escrever async na sua tag de script. Espero que esta série tenha esclarecido por que um navegador precisa para fornecer uma experiência na web mais rápida e fluida.

Usar o Lighthouse

Se você quer que seu código fique bom com o navegador, mas não tem ideia por onde começar, O Lighthouse é uma ferramenta que executa a auditoria de qualquer site e oferece uma relatar o que está sendo feito corretamente e o que precisa de melhoria. Ler a lista de auditorias também dá uma ideia do que importa para o navegador.

Saiba como avaliar o desempenho

Os ajustes no desempenho podem variar para diferentes sites. Por isso, é crucial medir o desempenho do seu site e decidir o que é melhor para ele. a equipe do Chrome DevTools tem alguns tutoriais sobre como medir o desempenho do seu site.

Adicionar uma política de recursos ao seu site

Caso queira tomar uma medida extra, a Política de recursos é uma nova recurso de plataforma da web que pode ser uma proteção para você quando estiver criando seu projeto. Ativando a política de recursos garante o determinado comportamento do app e evita que você cometa erros. Por exemplo, para garantir que o app nunca bloqueie a análise, execute-o em de scripts síncronos. Quando sync-script: 'none' estiver ativado, o JavaScript que bloqueia o analisador vai ser impedidos de serem executados. Isso evita que qualquer parte do seu código bloqueie o analisador e a navegador não precisa se preocupar em pausar o analisador.

Resumo

agradeço

Quando comecei a criar sites, eu quase só me preocupava com a forma que eu escrevia meu código e o que ajudaria a ser mais produtiva. Essas coisas são importantes, mas também devemos pensar em como navegador pega o código que escrevemos. Os navegadores modernos têm e continuam investindo em maneiras de fornecer uma experiência da Web melhor para os usuários. Ser legal com o navegador organizando nosso código, melhora a experiência do usuário. Espero que você se junte a mim na missão para ser legal com os navegadores!

Agradecemos muito a todos que revisaram os primeiros rascunhos desta série, incluindo, mas não se limitando para): Alex Russell, Paul Ireland, Meggin Kearney, Eric Bidelman, Mathias Bynens, Addy Osmani, Kinuko Yasuda, Nasko Oskov, e Charlie Reis.

Você gostou da série? Em caso de dúvidas ou sugestões para a próxima postagem, Adoraríamos ouvir sua opinião na seção de comentários abaixo ou no @kosamari no Twitter.