O HTTP / 2 prometeu acelerar significativamente a web e o Cloudflare há muito tempo implantava o acesso HTTP / 2 para todos os clientes. Mas um recurso do HTTP / 2, a priorização, não atendeu às expectativas. Não porque está fundamentalmente quebrado, mas por causa da implementação nos navegadores.
Hoje, o Cloudflare se oferece para alterar a priorização HTTP / 2, que dá aos nossos servidores controle sobre as decisões de priorização que realmente aceleram a Internet.
Historicamente, era o navegador que controlava como e quando baixar o conteúdo da web. Hoje, para todos os planos pagos, estamos fazendo mudanças radicais nesse modelo. Eles transferem o controle diretamente para o proprietário do site. Na guia "Velocidade" no painel do Cloudflare, os clientes podem ativar a "Priorização HTTP / 2 avançada": substitui as configurações padrão do navegador por um esquema de agendamento aprimorado, que acelera significativamente o acesso aos visitantes (em alguns casos, vimos um aumento de 50%). Com os funcionários do Cloudflare, os proprietários do site podem ir ainda mais longe e personalizar totalmente as configurações para suas necessidades específicas.
Situação atual
As páginas da Web consistem em
dezenas (às vezes centenas) de recursos individuais que são baixados e coletados pelo navegador no conteúdo final exibido. Isso inclui o conteúdo visível com o qual o usuário interage (HTML, CSS, imagens), bem como a lógica do aplicativo (JavaScript) para o site em si, publicidade, análises e beacons de rastreamento de marketing. Do ponto de vista do usuário, a sequência na qual esses recursos são carregados é muito importante: isso afeta o momento em que ele vê o conteúdo e pode interagir com a página.
Um navegador é, de fato, um mecanismo de processamento HTML que passa por um documento HTML e segue as instruções em ordem: do início ao fim do HTML, construindo a página à medida que ela se move. Os links da folha de estilos (CSS) informam ao navegador como estilizar o conteúdo da página, e o navegador atrasará a exibição do conteúdo até carregar a folha de estilo. Os scripts na página podem ter comportamentos diferentes. Se o script estiver marcado como "assíncrono" ou "pendente", o navegador poderá continuar processando o documento e simplesmente executar o script quando ele estiver disponível. Se o script não estiver marcado como assíncrono ou adiado, o navegador
DEVE parar de processar o documento até que o script seja carregado e executado. Esses scripts são chamados de "bloqueio" porque impedem o navegador de continuar processando o documento.
O documento HTML é dividido em duas partes. O título do documento <head> está no início e contém folhas de estilo, scripts e outras instruções do navegador necessárias para exibir o conteúdo. Depois que o cabeçalho é o corpo do documento <body>, ele contém o conteúdo real exibido na janela do navegador (embora scripts e folhas de estilo também possam estar no corpo). Até o navegador chegar ao corpo do documento, o usuário não tem nada para mostrar e a página permanece em branco. Portanto, é importante processar o cabeçalho o mais rápido possível. Se você estiver interessado nos detalhes, o site do
HTML5 Rocks tem um
ótimo tutorial sobre como os navegadores funcionam.
O navegador geralmente é responsável pela ordem em que os vários recursos necessários para construir a página e processar o documento são carregados. No HTTP / 1.x, há restrições sobre quantos objetos o navegador pode solicitar de qualquer servidor por vez (geralmente 6 conexões e apenas um recurso por vez por conexão), portanto, a ordem das solicitações é estritamente controlada pelo navegador. No HTTP / 2, a situação é completamente diferente. O navegador pode solicitar todos os recursos de uma só vez (pelo menos assim que descobrir sobre eles) e fornece ao servidor instruções detalhadas sobre como fornecer esses recursos.
Ordem ideal de carregamento de recursos
Para a maioria das peças, existe um pedido ideal no ciclo de carregamento da página que maximiza a disponibilidade da página para o usuário (e a diferença entre o pedido de carregamento ótimo e o não ideal pode atingir 50% ou mais).
Como descrito acima, antes que o navegador possa exibir qualquer conteúdo, ele é bloqueado por CSS e JavaScript na seção
<head>
. Nesse estágio, é mais lucrativo usar 100% do canal para carregar recursos de bloqueio, em vez de carregá-los em ordem, conforme eles estão escritos no código HTML. Isso permite que o navegador analise e execute cada elemento enquanto carrega o próximo recurso de bloqueio, o que cria um pipeline ideal.

O tempo de carregamento do script para carregamento paralelo ou seqüencial não difere, mas para carregamento sequencial, o primeiro script pode ser processado e executado durante o segundo carregamento.
Depois de carregar os recursos de bloqueio, a situação se torna um pouco mais interessante. Aqui, a carga ideal pode depender de um site específico ou mesmo de prioridades de negócios (seleção de conteúdo ou publicidade gerada pelo usuário ou análise, etc.). Um problema separado com as fontes, porque o navegador detecta as fontes desejadas após aplicar a folha de estilo ao conteúdo exibido. Portanto, quando o navegador descobrir a fonte, é necessário exibir o texto que já está pronto para exibição na tela. Qualquer atraso no carregamento da fonte resulta em nenhum texto na tela (ou o texto é exibido na fonte incorreta).
Como regra, algumas compensações precisam ser consideradas:
- Fontes e imagens personalizadas na parte visível da página (janela de visualização) devem ser carregadas o mais rápido possível. Eles afetam diretamente a experiência visual do usuário ao carregar a página.
- O JavaScript sem bloqueio deve ser carregado sequencialmente em relação a outros recursos JavaScript, para que cada um deles possa ser canalizado. O JavaScript pode incluir lógica de aplicativo personalizada, além de rastrear beacons para análises e marketing, e seu atraso pode levar a uma diminuição nos indicadores rastreados pela empresa.
- As imagens podem ser carregadas em paralelo. Os primeiros bytes do arquivo de imagem contêm seu tamanho, o que pode ser necessário para o layout do navegador, e o carregamento paralelo de imagens progressivas pode fornecer integridade visual após a transferência de cerca de 50% do volume total.
Dadas as compensações, na maioria dos casos, essa estratégia funciona bem:
- As fontes personalizadas são baixadas sequencialmente e compartilham a largura de banda disponível com as imagens no escopo.
- Imagens visíveis são carregadas em paralelo, compartilhando entre si a parte da largura de banda alocada a eles.
- Quando não houver mais fontes ou imagens visíveis:
- Os scripts sem bloqueio são carregados sequencialmente e compartilham a largura de banda disponível com imagens invisíveis (que estão fora do escopo).
- Imagens invisíveis são carregadas em paralelo, compartilhando entre si a parte da largura de banda alocada a eles.
Assim, o conteúdo visível para o usuário é carregado o mais rápido possível, a lógica do aplicativo é adiada ao mínimo e as imagens invisíveis são carregadas de forma a concluir o layout o mais rápido possível.
Exemplo
Para ilustrar, use uma página de categoria de produto simplificada de um site de comércio eletrônico típico:
- Azul - arquivo HTML da própria página.
- Verde - uma folha de estilo externa (arquivo CSS).
- Laranja - quatro scripts externos (JavaScript). Dois scripts de bloqueio na parte superior da página e dois scripts assíncronos. Os scripts de bloqueio são mostrados em um tom mais escuro de laranja.
- Vermelho é uma fonte da web personalizada.
- Violeta - 13 imagens. O logotipo da página e quatro imagens do produto são exibidas na janela de visualização; outras 8 imagens do produto requerem rolagem. As cinco imagens visíveis são indicadas por um tom mais escuro de púrpura.
Para simplificar, suponha que todos os recursos tenham o mesmo tamanho e cada carregamento em 1 segundo. O download de todos os recursos leva um total de 20 segundos, mas a ordem e o método de carregamento são extremamente importantes.

Aqui está como será o carregamento ideal de recursos em um navegador:

- A página fica em branco pelos primeiros 4 segundos ao carregar HTML, CSS e scripts de bloqueio: todos eles usam 100% de conexão.
- Na marca de 4 segundos, o plano de fundo e a estrutura da página são exibidos sem texto ou imagens.
- Após um segundo, em cerca de 5 segundos, o texto da página é exibido.
- No intervalo de 5 a 10 segundos, as imagens são baixadas, tremidas no início, mas muito rapidamente elas se tornam nítidas. Em cerca de 7 segundos, o resultado é quase indistinguível da versão final.
- Em cerca de 10 segundos, o carregamento de todo o conteúdo visual na parte visível da página é concluído.
- Nos próximos dois segundos, o JavaScript assíncrono é carregado e executado, executando qualquer lógica não crítica (análises, tags de marketing etc.).
- Durante os últimos 8 segundos, as imagens restantes são carregadas, caso o usuário role a página.
Priorização atual do navegador
Todos os mecanismos de navegador atuais implementam
várias estratégias de priorização , nenhuma das quais é ideal.
O Microsoft Edge e o Internet Explorer não oferecem suporte à priorização ; portanto, eles trabalham com as configurações HTTP / 2 padrão, que carregam tudo em paralelo, distribuindo uniformemente a largura de banda entre todos os recursos. O Microsoft Edge em versões futuras passará a usar o mecanismo Chromium, o que pode melhorar a situação. Mas, por enquanto, em nosso exemplo, o navegador fica preso no cabeçalho da página na maioria das vezes, pois as imagens atrasam a transmissão de scripts de bloqueio e folhas de estilo.

Visualmente, isso leva a uma experiência bastante dolorosa: o usuário olha para uma tela em branco por 19 segundos e, em seguida, há um atraso de 1 segundo para exibir o texto. Ao visualizar a animação abaixo, seja paciente, pois durante 19 segundos pode parecer que nada está acontecendo em uma tela em branco (embora seja):
O Safari carrega todos os recursos em paralelo , compartilhando a largura de banda com base em sua importância, de acordo com o Safari (recursos de bloqueio como scripts e folhas de estilo são mais importantes que imagens). As imagens são carregadas em paralelo, mas também simultaneamente com o conteúdo bloqueado.

Embora o Safari seja semelhante ao Edge no sentido de que tudo carrega ao mesmo tempo, alocar mais largura de banda aos recursos de bloqueio permite exibir o conteúdo muito antes:

- Após cerca de 8 segundos, o carregamento da folha de estilo e dos scripts está concluído, para que você possa começar a renderizar a página. Como as imagens foram carregadas em paralelo, elas também podem ser exibidas parcialmente (tremidas para imagens progressivas). Isso ainda é duas vezes mais lento que o cenário ideal, mas muito melhor que no Edge.
- Após cerca de 11 segundos, a fonte é carregada. Você pode exibir o texto. Nesse momento, mais dados estão sendo carregados para as imagens e elas estão ficando um pouco mais nítidas. Isso é comparável à situação em torno da marca de 7 segundos para um cenário de carregamento ideal.
- Nos 9 segundos restantes, as imagens ficam mais nítidas à medida que mais dados são baixados até que, finalmente, o processo seja concluído em 20 segundos.
O Firefox cria uma árvore de dependência que agrupa recursos e, em seguida, planeja que os grupos carreguem um após o outro ou compartilhem a largura de banda entre os grupos. Nesse grupo, os recursos compartilham largura de banda e carregam simultaneamente. As imagens são planejadas para serem carregadas após folhas de estilo que bloqueiam a renderização e carregadas em paralelo, mas scripts e folhas de estilo que bloqueiam a renderização também são carregados em paralelo e não se beneficiam do pipelining.

No nosso exemplo, isso acontece um pouco mais rápido do que no Safari, pois as imagens estão aguardando o carregamento da folha de estilo:

- Em cerca de 6 segundos, o conteúdo da página original é exibido com versões em segundo plano e embaçadas das imagens do produto (em comparação com 8 segundos no Safari e 4 segundos na melhor das hipóteses).
- Em 8 segundos, a fonte foi carregada e você pode exibir o texto juntamente com imagens um pouco mais nítidas do produto (comparado aos 11 segundos e 7 segundos do Safari, na melhor das hipóteses).
- Nos 12 segundos restantes, as imagens ficam mais nítidas à medida que o conteúdo restante é carregado.
O Chrome (e todos os navegadores baseados no Chromium) priorizam o inventário. Isso funciona muito bem para bloquear recursos que são carregados de maneira ideal, mas não tão bons para imagens. Cada imagem é carregada até 100% antes de iniciar a próxima.

Na prática, esse é um cenário de download quase ideal, com a única diferença de que as imagens são baixadas uma de cada vez e não em paralelo:

- Até 5 segundos, o carregamento do Chrome é idêntico ao cenário ideal, exibindo o plano de fundo no 4º segundo e o conteúdo de texto no 5º.
- Nos próximos 5 segundos, as imagens da área de visibilidade são carregadas uma de cada vez até que o processo seja concluído em cerca de 10 segundos (em comparação com o cenário ideal, quando são exibidas de forma ligeiramente desfocada por cerca de 7 segundos e se tornam mais nítidas pelos três segundos restantes).
- Depois que a parte visual da página é concluída em 10 segundos (idêntico ao cenário ideal), os 10 segundos restantes são gastos na execução de scripts assíncronos e no carregamento de imagens ocultas (assim como no cenário ideal).
Comparação visual
A diferença visual é bem diferente, embora tecnicamente carregar todo o conteúdo leve o mesmo tempo:

Priorização do lado do servidor
A priorização de HTTP / 2 é solicitada pelo cliente (navegador) e o servidor deve decidir o que fazer com base na solicitação.
Um grande número de servidores não suporta essa função e o restante atende a uma solicitação do cliente. Outra opção é decidir sobre a melhor priorização do lado do servidor com base na solicitação do cliente.
De acordo com a
especificação , a priorização de HTTP / 2 é uma árvore de dependência que requer conhecimento completo de todas as solicitações atuais para poder priorizar recursos em relação uns aos outros. Isso permite implementar estratégias incrivelmente complexas, mas é difícil implementá-lo bem no lado do navegador ou do servidor (como evidenciado por várias estratégias do navegador e diferentes níveis de suporte do servidor). Para simplificar o gerenciamento da priorização, desenvolvemos um esquema mais simples que ainda possui toda a flexibilidade necessária para o planejamento ideal.
O esquema de priorização do Cloudflare consiste em 64 "níveis" prioritários e, em cada nível, existem grupos de recursos que determinam como dividir a conexão entre si:

Primeiro, todos os recursos são baixados em um nível de prioridade mais alto e, em seguida, ocorre uma transição para um nível mais baixo.
Dentro de um determinado nível de prioridade, existem três grupos de simultaneidade diferentes:
- 0 : todos os recursos do grupo "0" são enviados seqüencialmente na ordem em que foram solicitados usando 100% de largura de banda. Somente após o carregamento de todos os recursos do grupo "0" são considerados outros grupos no mesmo nível.
- 1 : todos os recursos no grupo de simultaneidade "1" são enviados sequencialmente na ordem em que foram solicitados. A largura de banda disponível é distribuída igualmente entre o grupo de paralelismo "1" e o grupo de paralelismo "n".
- n : os recursos no grupo de simultaneidade "n" são transmitidos em paralelo, compartilhando a largura de banda disponível.
Na prática, o grupo de paralelismo "0" é útil para conteúdo crítico que precisa ser processado sequencialmente (scripts, CSS, etc.). O grupo "1" é útil para conteúdo menos importante que pode compartilhar largura de banda com outros recursos, mas onde os próprios recursos ainda se beneficiam do processamento seqüencial (scripts assíncronos, imagens não progressivas etc.). O grupo de simultaneidade "n" é útil para recursos que se beneficiam do processamento paralelo (imagens progressivas, vídeo, áudio, etc.).
Priorização padrão do Cloudflare
Com a opção de priorização avançada, a ordem “ideal” de carregamento de recursos, conforme descrito acima, é implementada. As prioridades específicas aplicadas são as seguintes:

Esse esquema permite enviar seqüencialmente recursos que bloqueiam a renderização, enviar imagens visíveis em paralelo e o restante do conteúdo da página com algum nível de compartilhamento de largura de banda para equilibrar o carregamento do aplicativo e do conteúdo. A
ressalva * Se detectável é que nem todos os navegadores distinguem entre diferentes tipos de folhas de estilo e scripts, mas ainda assim será muito mais rápido em todos os casos. Aceleração de 50%, especialmente para visitantes do Edge e Safari, não será nada incomum:

Definindo priorização com trabalhadores
O trabalho padrão mais rápido é ótimo, mas fica realmente interessante graças à capacidade de configurar a priorização com o suporte do Cloudflare Workers, para que os sites possam substituir a prioridade padrão dos recursos ou implementar seus próprios esquemas de priorização.
Se o trabalhador adicionar o cabeçalho
cf-priority
à resposta, os servidores de borda Cloudflare aplicarão a prioridade e a simultaneidade especificadas. O formato do cabeçalho é <priority> / <concurrency>, portanto, o
response.headers.set('cf-priority', “30/0”);
definirá a prioridade 30 e o paralelismo 0. para essa resposta. Da mesma forma, "30/1" definirá o paralelismo "1" e "30 / n" definirá o paralelismo para n.
Com essa flexibilidade, um site pode definir prioridade arbitrária de recursos para suas necessidades. Por exemplo, para aumentar a prioridade de alguns scripts assíncronos importantes ou imagens principais: eles são baixados mesmo antes de o navegador determinar que estão dentro do alcance.
Para informar sobre decisões de priorização, o tempo de execução dos trabalhadores também indica as informações solicitadas pelo navegador na priorização no objeto de solicitação, que são passadas ao destinatário dos eventos do trabalhador (request.cf.requestPriority). As prioridades de entrada são uma lista de atributos separados por ponto e vírgula. Parece algo assim:
weight=192;exclusive=0;group=3;group-weight=127
.
- weight : weight para priorizar o HTTP / 2.
- exclusive : o sinalizador HTTP / 2 exclusivo (1 para navegadores baseados em Chromium, 0 para outros).
- group : identificador de fluxo HTTP / 2 para o grupo de solicitações (diferente de zero para o Firefox).
- peso do grupo : peso HTTP / 2 para o grupo de solicitações (diferente de zero para o Firefox).
Este é apenas o começo.
A capacidade de configurar e controlar a prioridade das respostas é o principal componente para um ótimo trabalho futuro. Pretendemos introduzir nossas próprias otimizações avançadas, mas com o apoio dos trabalhadores, todos os sites e pesquisadores podem experimentar várias estratégias de priorização. Por meio do Apps Marketplace, as empresas também podem criar novos serviços de otimização sobre a plataforma de trabalho e disponibilizá-los para uso em outros sites.
Se você estiver em um plano Pro ou superior, vá para a guia "Velocidade" no painel Cloudflare e ative a "priorização HTTP / 2 avançada" para acelerar seu site.
