2011-11-03 17 views
17

tl; dr - Safari en iOS 5 está almacenado en caché tan duro que está destruyendo mi sitio.Problemas con la memoria caché de la página en iOS 5 Safari al navegar atrás/descargue el evento no disparado

Estoy luchando con la forma en que el navegador Safari en iOS 5 trata con la memoria caché de respaldo, a la que llaman "Page Cache". La forma en que se describe here explica muy bien el comportamiento.

En pocas palabras, la caché de página lo hace tan cuando salga de una página que “pausa” y cuando vuelva nos presiona “juego”.

Esto está causando problemas en todo mi sitio. Al usar el botón Atrás, la mayoría de los otros navegadores le mostrarán la página en el estado en que se cargó. No Safari en iOS 5, muestra la página tal como la dejó por última vez. Un ejemplo simple sería la desactivación de un botón de envío. Si utilizo Javascript para deshabilitar un botón de enviar, luego presento un formulario, cuando hace clic atrás, el botón de enviar seguirá estando deshabilitado. Esto ha sido un problema en otros navegadores, incluida la versión de escritorio de Safari, pero se soluciona al configurar el controlador de eventos onload en una función en blanco. Creo que esto le dice al navegador que invalide la memoria caché porque algo importante podría haber sucedido en esa función. Este truco no parece funcionar para Safari en iOS 5.

A continuación se muestra el problema reducido a lo esencial. Cuando cargues test.html, verás el texto "Texto original". Cuando haga clic en el enlace, ese texto cambiará a "Texto modificado: reenvío a la página siguiente", luego, en 3 segundos, se lo enviará a test2.html. Todo está bien hasta este punto en todos los navegadores. En todos los demás navegadores, al hacer clic en el botón Atrás, el texto que verá será "Texto original", pero en Safari para iOS 5 verá "Texto modificado: reenvío a la página siguiente".

¿Alguna sugerencia sobre cómo lidiar con esto?

Este es un ejemplo sencillo

test.html

<script> 
function changeText() { 
    el = document.getElementById("text"); 
    el.innerHTML = "Changed text - forwarding to next page"; 
    setTimeout("forward()",3000);  
} 
function forward() { 
    document.location.href = "test2.html"; 
} 
</script> 
<div id="text">Original Text</div> 
<a href="Javascript:changeText()">Click Here</a> 
<script> 
window.onunload = function(){}; 
</script> 

Test2.html

<div>Click back button</div> 

Este es un segundo ejemplo usando un poste de forma. Este es un simple ejemplo de cómo está funcionando mi aplicación. Cuando navegue de regreso a formtest2.asp, debería ver el valor del formulario publicado y el texto del div debería ser original.

FormTest.asp

<form method="post" action="formtest2.asp"> 
    Test: <input type="text" name="test"/> 
    <input type="submit" value="Submit"/> 
</form> 

formtest2.asp

<script> 
function changeText() { 
    el = document.getElementById("text"); 
    el.innerHTML = "Changed text - forwarding to next page"; 
    setTimeout("forward()",3000);  
} 
function forward() { 
    document.location.href = "test2.html"; 
} 
</script> 

<% 
Dim test 
test = Request("test") 
Response.Write("Test value: " & test & "<br />") 
%> 

<div id="text">Original Text</div> 
<a href="Javascript:changeText()">Click Here</a> 
<script> 
window.onunload = function(){}; 
</script> 

Test2.html

<div>Click back button</div> 
+0

Solo un poco más de información sobre esto. Parece que todos los navegadores que he probado (Firefox, IE, Safari Desktop) están disparando pagehide, y descargan, en ese orden. Safari en iOS 5 solo dispara la página. – Clarke

+0

Al abrir una pestaña nueva, el evento de descarga no se activa, solo pagehide. Al abrir una pestaña nueva, es de esperar que pueda navegar de nuevo a una pestaña anterior y ver la página tal como la dejó. El problema es que cuando navegamos de una página a la siguiente en la misma pestaña/ventana, el evento de descarga debe activarse por w3c, pero no es así. http://www.w3.org/TR/DOM-Level-2-Events/events.html. "El evento de descarga ocurre cuando la implementación DOM elimina un documento de una ventana o marco. Este evento es válido para elementos BODY y FRAMESET". – Clarke

+0

Cualquier solución que use location.reload() falla porque para esta función, Safari en ios 5 solo hará un GET, no un POST como todos los demás navegadores. – Clarke

Respuesta

1

He quedado con el mismo problema.
En iOS4, cuando navegue de página de inicio.html a 2.html, luego vuelva a la página de inicio.html, no se llamará a la js . cuando navegas homepage.html a 2.html, desde 2.html continúas yendo a 3.html, y luego de vuelta de 3 a 2 a la página de inicio, se llamará a JS ! Sí, ¡es terrible!
Pero en IOS5 MobileSafari, Siempre no se puede llamar :(Tal vez este es un error de caché en iOS5. Probé en iOS 5.0.0 y 5.0.1, consiguió el mismo resultado.

Pero cuando se implementa la evento onUnload en el elemento body, se puede solucionar el problema de retroceso en MobileSafari anterior. Simplemente cambié el <body> a <body onUnload=""> en homepage.html, luego de la página de inicio a 2.html, cuando regrese a la página de inicio, se llamará a la página de inicio de javascript Funciona en FF, Desktop Safari, Mobile Safari (iOS4)

Así que, ¿Cómo podemos hacer en iOS5? Lamentablemente, no he encontrado una solución. Pero mi aplicación web se ejecuta en un cliente nativo, me fijo esto añadiendo una llamada reload() de orígenes:

 
     if (isOS5_) 
     { 
      [webView stringByEvaluatingJavaScriptFromString:@"location.reload();"]; 
     } 

cuando webViewDidFinishLoad:

+0

He intentado agregar una recarga en la página cuando navego hacia ella, pero esto causa problemas en páginas que esperan una publicación de formulario. La recarga simplemente carga el URI sin publicar los datos del formulario. – Clarke

1

en mi sitio móvil, que han solucionado el problema con este pequeño código JS:

if ((/iphone|ipad.*os 5/i).test(navigator.appVersion)) { 
    window.onload=function() { 
     localStorage.setItem("href",location.href); 
    }; 
    window.onpopstate=function() { 
     var a=localStorage.getItem("href"), 
      b=location.href; 
     if (b!==a&&b.indexOf((a+"#"))===-1) { 
      document.body.style.display="none"; 
      location.reload(); 
     } 
    }; 
} 

Escenario:

al hacer clic en el enlace “Página 2” de “Page1”: Una vez hecho clic en “Page1” se acerca d, "Página2" está cargado y dispara la carga y muchos otros eventos.

[Página 1] -> haga clic en el enlace -> [Página 2] -> onload -> onpopstate -> ...

En este punto, si hace clic en el botón Atrás de su navegador, “Página 2” recibe cerrado y se carga "Página1" y dispara la carga y muchos otros eventos.

[Página 2] -> haga clic en el botón de retroceso -> [Página 1] -> onload -> onpopstate -> ...

Al hacer clic en el botón de vuelta en iOS5 hace que el cierre aparece “Page1” y “Página 2” pero la página no está cargada, la escala de la ventana gráfica se corrompe y el único evento disparado es onpopstate.

[Página2] -> haga clic en el botón Atrás -> [Página1] -> onpopstate.

La solución:

Los trabajos fijos alrededor de los eventos onload, onpopstate y el objeto localStorage.

onload es el primer evento administrado por el script, y dentro de este almacena el actual location.href en localStorage.

Si no hay ningún error, en onpopstate la ubicación actual.href y la href almacenadas deben ser las mismas y la secuencia de comandos no debe hacer nada.

Al utilizar Safari en IOS5, la página no se carga y el evento de carga no se activa, entonces location.href y la href almacenada son diferentes en el evento onpopstate.

En este caso simplemente oculte la página actual (para otro error en la ventana gráfica relacionada con esto) y vuelva a cargar la página con el objeto de ubicación.

+0

Gracias por la entrada, aunque no funcionará para mí. Dado que esto funciona para usted, es posible que desee agregar ipod a la declaración if. Tuve que hacer esto porque un iPod Touch es lo que uso para probar y tuve que agregarlo para hacerlo funcionar. Esta solución funciona bien para páginas de contenido dinámico, pero se descompone cuando navega de regreso a una página que espera un envío de formulario. El archivo location.reload() solo carga ese URI y no publica los valores de formulario originales. Aquí es donde mi ejemplo html anterior está incompleto. – Clarke

26

También estaba buscando una respuesta al mismo problema. Volver atrás en iOS 5 no ejecuta ningún javascript y simplemente deja la página en el estado anterior al que se fue o se redirigió.

Probando el raro truco de "onunload" encontrado en "Is there a cross-browser onload event when clicking the back button?" solo funcionó para iOS 4, no iOS 5 que no llama al evento como se esperaba. Nickolay señaló nuevas funciones en el kit web llamado "pageshow" y "pagehide", que son mucho más confiables que el ejemplo de Giuseppe.

  1. Se necesita el truco de este artículo: "Is there a cross-browser onload event when clicking the back button?" para que esto funcione en IOS 4.
  2. uso de este script que utiliza el nuevo evento para comprobar con seguridad si la página se ha cargado desde la memoria caché y forzar una recargar (evitando URLs cheques y almacenamiento local y también incluyen iPods) para iOS 5:

    <body onunload=""> 
    ... 
    <script type="text/javascript"> 
    if ((/iphone|ipod|ipad.*os 5/gi).test(navigator.appVersion)) { 
        window.onpageshow = function(evt) { 
        // If persisted then it is in the page cache, force a reload of the page. 
        if (evt.persisted) { 
         document.body.style.display = "none"; 
         location.reload(); 
        } 
        }; 
    } 
    </script> 
    
+0

Al final, esta solución es la misma que en el resto porque hacer una recarga no soluciona mi problema. Debajo, "Esta solución funciona bien para las páginas de contenido dinámico, pero se descompone cuando navega de regreso a una página que espera un envío de formulario. Location.reload() solo carga ese URI y no publica los valores de formulario originales". – Clarke

+1

@Clarke: Necesita escribir los parámetros POST que desea volver a enviar al marcado utilizando el código del lado del servidor (al igual que la forma en que está escribiendo la variable "prueba"). Inyecte elementos de entrada ocultos bajo el elemento de formulario para todas las variables que desee POSTAR de nuevo. Luego, utilizando el mismo código básico anterior, en lugar de hacer una recarga, simplemente envíe un formulario. – BrutalDev

+0

Esa parecía una buena solución, pero en la realidad no lo es. Ese evento a veces se dispara a veces no. Ni siquiera puedo explicar cómo repetir ese problema, intento abrir la página 1 y luego la página 2, luego hago clic atrás, el evento se dispara y luego repito un par de veces. – Rantiev

0

Después de encontrar la manera de evitar uno de los tema (s) que todos parecen tener en esto, yo me dura me gustaría compartir :)

Después de leer algunos temas relacionados sobre el tema, principalmente sobre el desbordamiento de pila "temas más candentes", manejar el "Caché de página" (http://www.webkit.org/blog/427/webkit-page-cache-i-the-basics/ y http://www.webkit.org/blog/516/webkit-page-cache-ii-the-unload-event/), verificando el evento "descargar" (developer.apple.com/library/IOS /ipad/#documentation/AppleApplications/Reference/SafariWebContent/HandlingEvents/HandlingEvents.html)/"pageshow" no tiene que ocuparse de la breve "aparición de página" en su estado anterior (no en el estado INICIAL de la página anterior, sino solo en la página como quedaba) mientras el usuario vuelve a la aplicación/o desbloquea su dispositivo/o regresa a la aplicación después de salir de ella.

Parece (para mí, al menos), que esta "página de fallo visible" se resolvió cuando hice la actualización para IOS6, al igual que hace 5 minutos; D

Yo era entonces capaz de usar mi aplicación web en Safari móvil como es normal, y luego de agregarlo a la pantalla de inicio, el comportamiento en caso de "cambio de aplicación" o "reinicio", con o sin caché borrada, es el mismo que su primer inicio: aparece una página EN BLANCO y luego su contenido (que puede ser la página correspondiente a la url que se guardó en la pantalla de inicio, o cualquier otro contenido cargado utilizando localStorage, por ejemplo [my case (..)]).

Para los eventos que pude ver, ni en los dispositivos IOS4 IOS5 pude lograr deshacerme de ese "problema de persistencia visual". Supongo que es por la forma en que funciona "Page Cache", pero ahora estoy ejecutando IOS6 en iPad, ya que el problema ya no existe, creo que el equipo de Safari debe haber mejorado la forma en que manejan las aplicaciones web de "pantalla de inicio" ()

Cuestiones relacionadas