Desenvolvimento

29 abr, 2013

Recarregamento de elementos posteriores ao onload

Publicidade

Duas boas práticas de desempenho são definir uma data de expiração futura e um atraso para o carregamento de elementos (especialmente scripts) até após o evento de onload. Mas acontece que a combinação dessas boas práticas leva a uma situação em que é difícil para os usuários renovar os dados. Sendo mais específico, apertar Recarregar (ou mesmo shift+Recarregar) não atualiza esses elementos cacheáveis e “preguiçosos” no Firefox , Chrome, Safari, Android e iPhone.

O que esperamos do botão Recarregar

Um navegador possui um cache (ou 10) no qual ele salva cópias das respostas http. Se o usuário achar que essas respostas cacheadas estão caducas, ele pode apertar o botão Recarregar pra ignorar o cache e buscar tudo novamente e, assim, se assegurar de que ele está vendo a última versão do conteúdo do website. Eu não consegui achar nada na especificação do HTTP que dita o comportamento do botão Recarregar, mas todos os navegadores possuem esse comportamento, até onde eu sei:

  • Se você clicar no Recarregar (ou control+R ou command+R), todos os elementos são então buscados novamente utilizando uma requisição GET condicional (com os validadores If-Modified-Since e If-None-Match). Se a resposta da versão do servidor não tiver mudanças, ele retorna um status “304 Not Modified” curto, sem resposta no corpo da mensagem (body). Se a resposta for que houve mudanças, então será “200 OK” e todo o corpo da resposta é enviado.
  • Se você clicar em shift+Reload (ou ctrl+Recarregar ou ctrl+shift+R ou command+shift+R) então todos os elementos são buscados novamente SEM os cabeçalhos de validação. Isso é menos eficiente, uma vez que cada resposta do corpo da mensagem é retornada, mas garante que qualquer resposta em cache, que esteja caduca, seja sobrescrita.

Apesar das datas de expiração, nossa expectativa é de que ao apertar Recarregar, tenhamos a última versão do website e com shift+Recarregar faremos isso de forma ainda mais agressiva.

Bem-vindo ao Reload 2.0

Nos tempos de Web 1.0, os elementos eram requisitados utilizando marcação HTML – IMG, SCRIPT, LINK etc. Com a Web 2.0, os elementos são frequentemente requisitados dinamicamente. Dois exemplos comuns são o carregamento de scripts assincronamente (ex.: Google Analytics) e dinamicamente, buscando imagens (ex:. em exibições de fotos e imagens abaixo da primeira “dobra”). Às vezes, esses elementos são requisitados depois que a janela carregou, para que assim a página principal possa renderizar mais rapidamente e oferecer uma experiência melhor ao usuário, melhores métricas etc. Se os elementos possuem uma data de expiração distante, o navegador precisa de uma inteligência extra para fazer a coisa certa.

  • Se o usuário navegar pela página normalmente (clicando em um link, digitando uma URL, utilizando um bookmark etc.) e caso o elemento dinâmico esteja em cache, o navegador deve usar a cópia em cache (supondo que a data de expiração ainda está por vir).
  • Se o usuário recarregar a página, o navegador deve buscar novamente todos os elementos, incluindo aqueles carregados dinamicamente na página.
  • Se o usuário recarregar a página, eu pensaria que os elementos recarregados através da ação devem ser requisitados de novo. Eles provavelmente incluem partes da construção básica da página e devem ser requisitados caso o usuário queira atualizar os conteúdos da página.
  • Mas o que o navegador deve fazer se o usuário recarregar a página e há elementos carregados depois do evento de carregamento? Alguns aplicativos web possuem sessões que podem durar por horas ou mesmo dias. Se o usuário não recarregar, deve cada elemento ser carregado dinamicamente por toda a sessão do aplicativo web, ignorando o cache?

Um exemplo

Vamos olhar para um exemplo: Recarregamento após onload.

Essa página carrega imagens e scripts usando cinco diferentes técnicas:

  1. marcação – a abordagem HTML básica: <img src= e <script src=
  2. dinamicamente no body – no body da página, há um bloco de script que cria uma imagem e um script de um elemento dinâmico que configura o SRC fazendo com que o elemento seja buscado. Esse código é executado antes do carregamento.
  3. Onload – Uma imagem e um script são criados dinamicamente pelo evento que causou o carregamento.
  4.  1ms post-onload – uma imagem e um script são criados dinamicamente chamando a resposta setTimeout de 1 milisegundo no evento causador do carregamento.
  5. 5 second post-on – uma imagem e um script são criados dinamicamente chamando a resposta setTimeout de de 5 segundos no evento causador do carregamento.

Todas as imagens e os scripts têm uma data de expiração de um mês no futuro. Se o usuário clicar em Recarregar, quais das técnicas devem ser usada para isso? Certamente esperamos que as técnicas 1 e 2 resultem na renovação dos elementos. E até gostaria de ver o número 3 fazer o mesmo. Creio que a técnica 4 deveria funcionar, mas duvido que algum navegador faça isso, e o número 5 provavelmente não deverá causar coisa alguma. Estabeleça as suas expectativas e então dê uma olhada na tabela abaixo.

Os resultados

Antes de irmos direto aos resultados dos testes de recarregamento, vamos dar uma olhada no que acontece se o usuário apenas navegar na página. Isso é alcançado ao clicar no link “try again” do exemplo. Nesse caso, nenhum dos elementos é renovado. Todos os elementos foram salvos em cache com uma data de expiração de um mês à frente, portanto todos os navegadores que testei leem a página a partir do cache. Isso é bom e é o que esperamos que aconteça.

Mas o comportamento diverge quando olhamos para os resultados de carregamento capturados na tabela abaixo.

Tabela 1. elementos renovados ao recarregar

Técnica elemento Chrome 25 Safari 6 Android Safari/543iPhone Firefox 19 IE 8, 10 Opera 12
marcação Imagem 1 S S S S S S S
Script 1 S S S S S S S
dinamicamente Imagem 2 S S S S S S S
Script 2 S S S S S S S
onload Imagem 3 S S S
Script 3 S S
1ms após onload Imagem 4 S
Script 4 S
5seg após onload Imagem 5
Script 5

Os resultados para Chrome, Safari, Android mobile e Safari mobile são os mesmos. Quando você clica em Recarregar nesses navegadores, os elementos da página não buscados novamente (elementos 1 e 2), mas não os elementos carregados após o manipulador onload.

O Firefox é interessante. Ele carrega os quatro elementos da página, mais a imagem do manipulador onload, mas não o script (script 3). Curioso.

O IE 8 e 10 são iguais: eles carregam os quatro elementos na página e também a imagem e o script do manipulador onload (elementos 1-3). Não testei o IE 9, mas acredito que seja igual.

O Opera teve os melhores resultados, na minha opinião. Ele renovou todos os elementos da página principal, o manipulador onload e aquele 1 milissegundo depois do onload (elementos 1-4), mas não renovou os elementos 5 segundos depois do onload (imagem 5 e script 5). E faço uma provocação quanto a isso. Se eu aumentar o tempo de 1 milissegundo para 50 milissegundos, então a imagem e o script 4 não são recarregados. Acho que isso seja uma condição temporal em que o Opera ainda pode estar baixando os elementos do manipulador onload quando esses primeiros elementos são criados e são então igualmente renovados. Para verificar isso mais a fundo, eu aumentei o atraso para 500 milissegundos e confirmei que os elementos não foram renovados, mas o tempo de resposta de todos os elementos aumentou para 1 segundo (antes era instantâneo) e isso fez com que a imagens e o script 4 fossem recarregados, mesmo o atraso sendo de 500 milissegundos depois do onload.

Note que pressionar shift+Recarregar (e outras combinações) não altera os resultados.

Para viagem

Um tanto quanto esotérico? Talvez. Esse é um mergulho em um tema bem específico. Eu garanto isso. Mas eu tenho alguns poréns:

Se você é um desenvolvedor utilizando datas de expiração bem “para frente” e lazy loading, você talvez obtenha resultados inesperados quando alterar um elemento e clicar em Recarregar, mesmo com shift+Reload. Se você não está vendo a versão mais recente de seus elementos, talvez seja preciso limpar o seu cache.

Isso não é uma questão apenas para desenvolvedores web. Isso afeta usuários também. Muitos sites utilizam elementos lazy loading e datas de expiração futuras, incluindo 8 entre os 10 maiores: Google, YouTube, Yahoo!, Microsoft Live, Tencent QQ, Amazon e Twitter. Se você recarregar qualquer um com um sniffer de pacotes aberto em um dos quatro navegadores listados, irá ver um padrão curioso: elementos cacheáveis carregados antes que o onload tivesse uma resposta de status 304, enquanto outros, após o onload, são lidos a partir do cache e não são renovados. A única forma de se certificar de que possui uma versão recente é limpar o cache, acabando com as vantagens do botão de recarregar.

Aqui temos um gráfico exibindo as requisições feitas quando o site da Amazon é recarregado no Chrome. A linha vertical vermelha marca o evento de onload. Perceba como os elementos anteriores ao onload recebem códigos de status 304. Logo após o onload há algumas imagens que não são cacheáveis, portanto são renovadas e retornam código 200. As imagens carregadas após o onload são todas lidas a partir do cache, portanto qualquer atualização desses elementos é perdida.

 

reload-waterfall

 

Finalmente, mesmo que o comportamento dos diferentes navegadores variem, vale a pena investigar o porquê. Nesse caso, deveríamos tornar o recarregamento mais consistente e fazê-lo renovar os elementos, mesmo aqueles carregados dinamicamente no manipulador onload.

***

Artigo traduzido pela Redação iMasters, com autorização do autor. Publicado originalmente em http://www.stevesouders.com/blog/2013/02/26/reloading-post-onload-resources/