Comunicación entre diferentes ventanas en el mismo dominio [duplicado]
Frecuentes
Visto 1,960 equipos
5
Estoy creando una aplicación que realiza una gran cantidad de descargas y procesamientos de datos del lado del cliente. El procesamiento de datos está aislado de la aplicación principal al procesarse en un iframe que reside en un subdominio. Es este iframe el que descarga los datos. La comunicación es vía postMessage.
Todo funciona bien, excepto que podría ser mejor.
Si el usuario abre pestañas/ventanas adicionales, la aplicación actualmente vuelve a cargar todos los datos e incluso puede duplicar el trabajo de procesamiento, lo cual no es un problema aparte de que ralentiza todo y las páginas tardan más en cargarse.
Lo que me gustaría hacer es que cada pestaña/ventana de nivel superior se comunique solo con el iframe de procesamiento, que podría restablecerse si se cierra la ventana original. El problema es que estos no se abren a través de javascript, sino a través de los métodos normales del navegador para abrir enlaces en pestañas, por lo que no puedo obtener una referencia al iframe que se necesita para enviar un mensaje.
¿Puedo comunicar de todos modos la referencia de la ventana para el iframe a las otras pestañas para que puedan comunicarse con él a través de un mensaje posterior? ¿Se podría lograr esto de alguna manera usando trabajadores compartidos?
Me doy cuenta de que podría usar trabajadores compartidos para toda la tarea de procesamiento, pero esto tendría sus propios problemas ya que los datos provienen de dominios de terceros, a los que no se puede acceder desde dentro de un trabajador.
Solo se necesita compatibilidad con las últimas versiones de todos los principales navegadores.
Editar: acabo de descubrir que SharedWorker aún no está implementado en Firefox, así que supongo que eso no funcionará. ¿Alguna otra forma en que podría lograr esto?
Edición 2: he descubierto que puedes usar:
var win = window.open('', 'my_window_name');
para capturar una referencia a un iframe desde cualquier otra ventana. Sin embargo, si el iframe aún no existe, lo abrirá como una ventana. Incluso si se cierra inmediatamente, provoca un parpadeo y provoca los mensajes de 'ventana emergente bloqueada', lo que lo hace inutilizable.
1 Respuestas
3
En caso de que alguien más encuentre esto, he encontrado una solución. Es un poco hacky y requiere más pruebas. Pero hasta ahora está funcionando. Funciona entre dominios si es necesario.
Utiliza una combinación de dos trucos.
El primero es usar
remote_window = window.open("", "remote_window_name");
para obtener una referencia a la ventana. Esto funciona porque si una ventana ya está abierta con el nombre dado, se le devuelve una referencia en lugar de abrir una nueva ventana.
Sin embargo, tiene el problema de que si el iframe no existe, aparecerá una nueva ventana. El almacenamiento local se utiliza para evitar esto. Cuando se carga una ventana/pestaña, comprueba localStorage para ver si ya hay otra página con un iframe compartido. Si no, inserta el iframe y establece una bandera en el almacenamiento local para decir que está disponible.
Como último recurso, si la ventana aún se abre, se usa un bloque de prueba para cerrar la ventana recién abierta. El bloque try evita errores entre dominios. Esto significa que lo peor que sucederá es que el usuario vea una ventana emergente y desaparezca o verá el mensaje 'habilitar ventanas emergentes'. Todavía tengo que lograr activar esto en las pruebas: es solo un caso extremo de retroceso.
try {
if(store_window.location.href === "about:blank" ){
remote_window.close();
remote_window = insertIfame();
}
} catch(err) {
}
Se agrega un evento de descarga que elimina la bandera en caso de que se cierre la página.
También se crea un setInterval que actualiza constantemente un indicador de tiempo de espera. Lo tengo funcionando 4 veces por segundo; cuando se carga una segunda ventana/pestaña, comprueba que el indicador iframe no haya expirado antes de intentar comunicarse con él. Esta es una pequeña sobrecarga, pero mucho menor que el costo para mí de tener ese segundo iframe cargado. Esto tiene el propósito de evitar datos obsoletos si el navegador falla o la descarga no se activa por algún motivo. Incluyo un pequeño margen de maniobra al verificar el tiempo de espera, actualmente 1 segundo, en caso de que la ventana principal esté atascada en un bucle. El margen de maniobra está solo en el tiempo de espera, no en el evento de descarga que elimina la bandera por completo.
La bandera debe verificarse cada vez que se envía un mensaje en caso de que la ventana original con el iframe se haya cerrado. Cuando esto sucede, el iframe se reinserta en la primera ventana abierta que lo requiere y la bandera se restablece.
Enviar mensajes de vuelta es fácil. Simplemente use la propiedad event.source de receiveMessage; esto apunta a la ventana de envío.
Un último caso extremo a tener en cuenta es si la ventana principal se cierra mientras su iframe está en medio del proceso para una ventana secundaria. Teóricamente, esto podría solucionarse mediante el uso de un evento de descarga en el iframe para enviar un mensaje a cualquier ventana con datos en proceso. Pero todavía tengo que implementarlo y es posible que no termine antes de que se descargue la página. Otra forma de lidiar con esto sería tener un tiempo de espera en la ventana secundaria que verifique el indicador y vuelva a intentarlo, probablemente seguiré esta ruta ya que los mensajes ya tienen tiempos de espera adjuntos.
Respondido el 13 de junio de 12 a las 15:06
No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas javascript postmessage or haz tu propia pregunta.
Supongo que los trabajadores web no son una opción, ya que solo funcionarán en IE 10 ;-) - Ja͢ck
usar html5 localstorage, ¿puede ser? - pahnin
@pahnin Esa es una idea. Haré un experimento. - SystemicPlural
@pahnin No puedo ver una forma de convertir la referencia de la ventana en una cadena y viceversa. Esto también sería un problema si se usaran SharedWorkers. - SystemicPlural
@SystemicPlural probablemente sea más fácil simplemente almacenar los resultados y/o el progreso del proceso de ejecución prolongada en
localStorage
(Creo que eso es lo que pahnin también podría haber significado). Luego, puede verificar su estado periódicamente y mostrar los resultados cuando haya terminado. Las cosas de la ventana a la cadena de referencia a la ventana suenan como si fueran frágiles y engañosas. - Flambino