Ajax, botão Voltar e atualizações de DOM

113

Se o javascript modificar o DOM na página A, o usuário navega para a página B e, em seguida, clica no botão voltar para voltar à página A. Todas as modificações no DOM da página A são perdidas e o usuário é apresentado com a versão que foi originalmente recuperada do servidor.

Funciona assim no stackoverflow, reddit e muitos outros sites populares. (tente adicionar um comentário de teste a esta questão, em seguida, navegue para uma página diferente e clique no botão Voltar para voltar - seu comentário "desaparecerá")

Isso faz sentido, mas alguns sites (apple.com, basecamphq.com etc) estão de alguma forma forçando o navegador a fornecer ao usuário o estado mais recente da página. (vá para http://www.apple.com/ca/search/?q=ipod , clique no link Downloads na parte superior e clique no botão Voltar - todas as atualizações de DOM serão preservadas)

de onde vem a inconsistência?

lubos hasko
fonte
Curiosamente, a Apple está se lembrando do estado sem modificar o hash .. hmmm
James
Parece que a Apple está apenas manipulando o cache de resposta
BigBlondeViking
Como outros já sugeriram, isso não é algo relacionado com javascript ou ajax. Você deve remover essas marcas para obter as respostas corretas.
BYK
O exemplo da Apple é ruim. Se você contratar uma área de busca [ex: produtos], clique no seu link e pressione voltar, o DOM não é preservado. você está procurando uma solução Hash que muitos sugeriram.
BigBlondeViking
Quando eu aperto o botão Voltar, a Apple não lembra em qual página de resultados de pesquisa eu estava. Usando o IE7. Você precisa de uma solução hash. Veja: Facebook.
Josh Stodola

Respostas:

106

Uma resposta: entre outras coisas, os eventos de descarregamento fazem com que o cache de retorno / encaminhamento seja invalidado .

Alguns navegadores armazenam o estado atual de toda a página da web no chamado "bfcache" ou "cache de página". Isso permite que eles renderizem novamente a página muito rapidamente ao navegar por meio dos botões voltar e avançar e preserva o estado do DOM e todas as variáveis ​​JavaScript. No entanto, quando uma página contém eventos onunload, esses eventos podem colocar a página em um estado não funcional e, portanto, a página não é armazenada no bfcache e deve ser recarregada (mas pode ser carregada do cache padrão) e recarregada renderizado do zero, incluindo a execução de todos os gerenciadores onload. Ao retornar a uma página através do bfcache, o DOM é mantido em seu estado anterior, sem a necessidade de disparar manipuladores onload (porque a página já está carregada).

Observe que o comportamento do bfcache é diferente do cache do navegador padrão em relação ao Cache-Control e outros cabeçalhos HTTP. Em muitos casos, os navegadores armazenam em cache uma página no bfcache mesmo que não seja armazenada no cache padrão.

O jQuery anexa automaticamente um evento de descarregamento à janela, então, infelizmente, o uso do jQuery desqualificará sua página de ser armazenada no bfcache para preservação de DOM e avanço / retrocesso rápido. [Atualização: isso foi corrigido no jQuery 1.4 para que se aplique apenas ao IE]

Milhas
fonte
3
você acertou em cheio. ambos, reddit e stackoverflow estão usando jquery enquanto basecamp e apple estão usando prototypejs. isso explica praticamente tudo.
lubos hasko
+1 interessante (mas não cross browser) a questão é muito diferente de quando começou ...
BigBlondeViking
1
provavelmente será cross-browser porque também posso reproduzi-lo no meu Internet Explorer. Tenho certeza que todo navegador com javascript habilitado teve que lidar com esse problema de qualquer maneira. mas isso é realmente uma bagunça, quando você pensa sobre isso, o botão Voltar deve sempre levar as pessoas à página que viram pela última vez com todas as atualizações de DOM, estado de javascript etc. os desenvolvedores não devem quebrar isso fazendo algo no evento de descarregamento e se o fizerem, os navegadores da web não devem tentar corrigir o problema deixando de usar o bfcache. todo o evento de descarregamento é uma grande piada. Tenho certeza de que 99% das vezes é usado para corrigir vazamentos de memória.
lubos hasko
1
Especificamente, vazamentos de memória do IE. :) O evento jQuery unload também acontece para corrigir um bug (completamente não relacionado) no Firefox 2. Mas é desnecessário para outros navegadores. dev.jquery.com/ticket/3015 Suponho que já ouvi falar de outros usos para onunload, como rastreamento de cliques de saída ou salvamento de estado de webapp, mas nunca tive um motivo para usá-lo sozinho e se os desenvolvedores quiserem sites mais lentos e dolorosos para seus usuários (eu odeio como navegar de volta para as páginas de comentários do reddit redefine o estado de comentário recolhido), essa é sua prerrogativa.
Milhas de
1
O evento unload é anexado apenas para o IE, não para o firefox e o chrome. A última versão do safari preserva o estado dom sem que o desenvolvedor tenha que fazer nada.
David
15

Tenho tentado fazer com que o Chrome se comporte como o Safari, e a única maneira que descobri que funciona é definindo Cache-control: no-storenos cabeçalhos. Isso força o navegador a buscar novamente a página do servidor quando o usuário pressiona o botão Voltar. Não é o ideal, mas é melhor do que ver uma página desatualizada.

Nornagon
fonte
5
Esta é a resposta correta para a pergunta original. Se você quiser forçar uma recarga do servidor no botão Voltar, use o cache-control 'no-store, no-cache, must-revalidate'. O Chrome não quer loja e o IE quer revalidação obrigatória. Para outros navegadores (e w3c), sem cache é suficiente.
woens
3

O Facebook lembra o estado da página modificando o identificador hash no URL para solicitações de ajax. Essas alterações são registradas no histórico do navegador, portanto, quando o usuário clica no botão Voltar, o hash muda para o que era antes. Portanto, está implícito que você precisará de algum Javascript para monitorar o identificador has e reagir quando ele é alterado pelo navegador. Andreas Blixt tem um script de monitoramento de hash disponível .

Josh Stodola
fonte
a partir de hoje ele não morre, então pode me dizer o que o Facebook faz agora
Ravinder Payal
3

Isso não tem nada a ver com o símbolo hash (#).

Se você verificar os cabeçalhos HTTP da apple, está simplesmente armazenando a página em cache.

Luca Matteis
fonte
O exemplo da Apple é ruim, eles não estão "salvando" o estado da página, sua suposição de que o DOM foi preservado incorretamente
BigBlondeViking
2

Usar o identificador de hash / fragmento de URL é uma maneira bastante comum de conectar / lembrar o estado em um aplicativo da web que depende de atualizações Ajax e DOM.

Confira o projeto Really Simple History para algumas idéias. É possível monitorar a URL para mudanças no hash, e rsh faz isso, levando em consideração as diferenças do navegador.

Peter
fonte
1

Para qualquer pessoa com problemas com Railse isso - seu problema não é o bfcache (pensei que fosse) - é a turbolinksjoia. Aqui está como removê-lo.

Esperançosamente, isso vai poupar algum tempo e bater sua cabeça contra a parede.

Yuval Karmi
fonte
0

O que você está procurando é algum tipo de gerenciamento de hash de URL. O # no url é apenas para o lado do cliente.

Ao alterar o estado da parte traseira com JS, você atualiza os dados no # do url.

Além disso, você adiciona algum tipo de pesquisa que monitora se o hash mudou e carrega o estado da página com base nos novos dados do hash.

Dê uma olhada neste:

http://ajaxpatterns.org/Unique_URLs

BigBlondeViking
fonte
3
isso não tem nada a ver com o símbolo hash.
Luca Matteis
3
Você está errado, ele está procurando a maneira mais comum de preservar o estado da página em uma solução AJAX.
BigBlondeViking