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

Mariko Kosaka

O que acontece na navegação

Esta é a segunda parte de uma série de quatro postagens no blog que aborda o funcionamento interno do Chrome. Na postagem anterior, vimos como diferentes processos e linhas de execução lidam com diferentes partes de um navegador. Nesta postagem, vamos entender melhor como cada processo e linha de execução se comunicam para mostrar um site.

Vamos analisar um caso de uso simples da navegação na Web: você digita um URL em um navegador, que busca dados da Internet e exibe uma página. Nesta postagem, vamos ver a parte em que um usuário solicita um site e o navegador se prepara para renderizar uma página, também conhecida como navegação.

Isso começa com um processo do navegador

Processos do navegador
Figura 1: interface do navegador na parte superior, diagrama do processo do navegador com interface, rede e linha de execução de armazenamento na parte inferior

Conforme abordado na parte 1: arquitetura de CPU, GPU, memória e vários processos, tudo fora de uma guia é processado pelo processo do navegador. O processo do navegador tem linhas de execução, como a de IU, que desenha botões e campos de entrada do navegador, a linha de execução de rede que lida com a pilha de rede para receber dados da Internet, a linha de execução de armazenamento que controla o acesso aos arquivos e muito mais. Quando você digita um URL na barra de endereço, sua entrada é processada pela linha de execução de interface do processo do navegador.

Navegação simples

Etapa 1: processar entradas

Quando um usuário começa a digitar na barra de endereço, a primeira coisa que a linha de execução de interface faz é "Esta é uma consulta de pesquisa ou um URL?". No Chrome, a barra de endereço também é um campo de entrada de pesquisa. Por isso, a linha de execução de IU precisa analisar e decidir se vai enviar você a um mecanismo de pesquisa ou ao site solicitado.

Como processar entradas do usuário
Figura 1: linha de execução de IU perguntando se a entrada é uma consulta de pesquisa ou um URL

Etapa 2: iniciar a navegação

Quando um usuário pressiona Enter, a thread de interface inicia uma chamada de rede para obter o conteúdo do site. O ícone de carregamento de carregamento é exibido no canto de uma guia, e a linha de execução da rede passa por protocolos apropriados, como busca DNS e estabelecimento de conexão TLS para a solicitação.

Início da navegação
Figura 2: a linha de execução de IU se comunicando com a linha de execução de rede para navegar para meusite.com

Nesse ponto, o encadeamento da rede pode receber um cabeçalho de redirecionamento do servidor, como HTTP 301. Nesse caso, a linha de execução de rede se comunica com a linha de execução de IU que o servidor está solicitando redirecionamento. Em seguida, outra solicitação de URL será iniciada.

Etapa 3: ler resposta

Resposta HTTP
Figura 3: cabeçalho de resposta que contém o tipo de conteúdo e o payload, que é o dado real

Quando o corpo da resposta (payload) começa a chegar, a linha de execução da rede analisa os primeiros bytes do stream, se necessário. O cabeçalho "Content-Type" da resposta indica o tipo dos dados. No entanto, como eles podem estar ausentes ou errados, a detecção de tipo MIME é feita aqui. Essa é uma "empresa complicada", conforme comentado no código-fonte. Leia o comentário para saber como diferentes navegadores tratam os pares de conteúdo, tipo e payload.

Se a resposta for um arquivo HTML, a próxima etapa será passar os dados para o processo do renderizador, mas se for um arquivo zip ou algum outro arquivo, isso significa que é uma solicitação de download, portanto, é necessário passar os dados para o gerenciador de download.

Detecção de tipo MIME
Figura 4: linha de execução de rede que pergunta se os dados de resposta são HTML de um site seguro

É também nesse local que acontece a verificação de SafeBrowsing. Se o domínio e os dados de resposta parecerem corresponder a um site malicioso conhecido, os alertas de thread de rede exibirão uma página de aviso. Além disso, a verificação de Cross read Read Blocking (CORB) acontece para garantir que os dados confidenciais entre sites não cheguem ao processo do renderizador.

Etapa 4: encontrar um processo de renderizador

Depois que todas as verificações forem concluídas e a linha de execução de rede estiver confiante de que o navegador acessará o site solicitado, a linha de execução de rede vai informar à linha de execução de IU que os dados estão prontos. Em seguida, a linha de execução de IU encontra um processo do renderizador para continuar a renderização da página da Web.

Encontrar processo do renderizador
Figura 5: linha de execução de rede informando à linha de execução de IU para encontrar o processo do renderizador

Como a solicitação de rede pode levar várias centenas de milissegundos para receber uma resposta, uma otimização para acelerar esse processo é aplicada. Quando a linha de execução de IU envia uma solicitação de URL para o thread de rede na etapa 2, ela já sabe para qual site está navegando. A linha de execução de IU tenta encontrar ou iniciar proativamente um processo de renderização em paralelo à solicitação de rede. Dessa forma, se tudo correr conforme o esperado, um processo do renderizador já estará na posição de espera quando a linha de execução da rede receber dados. Esse processo em espera pode não ser usado se a navegação redirecionar entre sites. Nesse caso, pode ser necessário um processo diferente.

Etapa 5: confirmar navegação

Agora que os dados e o processo do renderizador estão prontos, uma IPC é enviada do processo do navegador para o processo do renderizador para confirmar a navegação. Ele também transmite o fluxo de dados para que o processo do renderizador continue recebendo dados HTML. Depois que o processo do navegador detectar a confirmação de que a confirmação ocorreu no processo do renderizador, a navegação estará completa e a fase de carregamento do documento será iniciada.

Nesse momento, a barra de endereço é atualizada, e o indicador de segurança e a interface de configurações do site refletem as informações da nova página. O histórico da sessão da guia será atualizado para que os botões "Voltar/Avançar" avancem no site ao qual você acabou de navegar. Para facilitar a restauração de guias/sessão ao fechar uma guia ou janela, o histórico da sessão é armazenado em disco.

Confirmar a navegação
Figura 6: IPC entre o navegador e os processos do renderizador, solicitando a renderização da página

Etapa extra: carregamento inicial concluído

Depois que a navegação é confirmada, o processo do renderizador continua carregando recursos e renderiza a página. Abordaremos os detalhes do que acontece nessa fase na próxima postagem. Depois que o processo do renderizador "conclui" a renderização, ele envia uma IPC de volta ao processo do navegador. Isso acontece depois que todos os eventos onload foram disparados em todos os frames da página e terminaram a execução. Nesse momento, a linha de execução de IU interrompe o ícone de carregamento na guia.

Digo "finishes" porque o JavaScript do lado do cliente ainda pode carregar recursos adicionais e renderizar novas visualizações depois desse ponto.

Carregamento da página concluído
Figura 7: IPC do renderizador para o processo do navegador para notificar que a página foi "carregada"

A navegação simples foi concluída! Mas o que acontecerá se um usuário inserir outro URL para a barra de endereços? Bem, o processo do navegador passa pelas mesmas etapas para navegar até o site diferente. Mas, antes disso, é necessário verificar no site renderizado se ele se importa com o evento beforeunload.

O beforeunload pode criar o alerta "Sair deste site?" quando você tenta sair ou fechar a guia. Tudo dentro de uma guia, incluindo seu código JavaScript, é processado pelo renderizador. Dessa forma, o processo do navegador precisa verificar com o processo atual do renderizador quando uma nova solicitação de navegação aparece.

manipulador de eventos beforeunload
Figura 8: IPC do processo do navegador para um processo do renderizador informando que ele está prestes a navegar para um site diferente

Se a navegação tiver sido iniciada pelo processo do renderizador (como o usuário clicou em um link ou o JavaScript do lado do cliente executou window.location = "https://newsite.com"), o processo do renderizador vai verificar primeiro os gerenciadores beforeunload. Em seguida, ele passa pelo mesmo processo de navegação iniciada pelo processo do navegador. A única diferença é que a solicitação de navegação é iniciada do processo do renderizador para o processo do navegador.

Quando a nova navegação é feita para um site diferente do renderizado atualmente, um processo de renderização separado é chamado para lidar com a nova navegação, enquanto o processo de renderização atual é mantido para processar eventos como unload. Para mais informações, consulte uma visão geral dos estados do ciclo de vida da página e como você pode se conectar a eventos com a API Page Lifecycle.

nova navegação e descarregamento
Figura 9: duas IPCs de um processo de navegador para um novo processo de renderizador informando para renderizar a página e informando o processo antigo de descarregamento

No caso do Service Worker

Uma mudança recente nesse processo de navegação é o lançamento do service worker. O service worker é uma maneira de escrever proxy de rede no código do aplicativo. Isso permite que os desenvolvedores Web tenham mais controle sobre o que armazenar em cache localmente e quando receber novos dados da rede. Se o service worker estiver configurado para carregar a página do cache, não será necessário solicitar os dados da rede.

É importante lembrar que o service worker é um código JavaScript executado em um processo de renderização. Mas, quando a solicitação de navegação chega, como o processo do navegador sabe que o site tem um service worker?

Pesquisa de escopo do service worker
Figura 10: a linha de execução de rede no processo do navegador procurando o escopo do service worker

Quando um service worker é registrado, o escopo dele é mantido como referência. Leia mais sobre o escopo neste artigo sobre o ciclo de vida do Service Worker. Quando ocorre uma navegação, a linha de execução de rede verifica o domínio em relação aos escopos registrados do service worker. Se um service worker estiver registrado para esse URL, a linha de execução de interface encontrará um processo de renderização para executar o código do service worker. O service worker pode carregar dados do cache, eliminando a necessidade de solicitar dados da rede, ou pode solicitar novos recursos da rede.

navegação de service worker
Figura 11: a linha de execução de IU em um processo do navegador iniciando um processo de renderização para processar service workers. Uma linha de execução de worker em um processo de renderizador, em seguida, solicita dados da rede

Você pode ver que essa viagem de ida e volta entre o processo do navegador e o processo do renderizador pode resultar em atrasos se o service worker decidir solicitar dados da rede. O pré-carregamento de navegação é um mecanismo para acelerar esse processo carregando recursos em paralelo à inicialização do service worker. Ele marca essas solicitações com um cabeçalho, permitindo que os servidores decidam enviar conteúdo diferente para essas solicitações. Por exemplo, somente dados atualizados em vez de um documento completo.

Pré-carregamento de navegação
Figura 12: a linha de execução de IU em um processo do navegador iniciando um processo de renderizador para lidar com o service worker enquanto inicia a solicitação de rede em paralelo

Conclusão

Nesta postagem, vimos o que acontece durante uma navegação e como o código do seu aplicativo da Web, como cabeçalhos de resposta e JavaScript do lado do cliente, interage com o navegador. Saber as etapas que o navegador realiza para receber dados da rede facilita o entendimento do motivo pelo qual APIs como o pré-carregamento de navegação foram desenvolvidas. Na próxima postagem, veremos como o navegador avalia nosso HTML/CSS/JavaScript para renderizar páginas.

Você gostou da postagem? Se você tiver dúvidas ou sugestões para a próxima postagem, queremos saber sua opinião na seção de comentários abaixo ou @kosamari no Twitter.

A seguir: funcionamento interno de um processo de renderizador