La API de mensajería de canal permite que los iframes y los trabajadores se comuniquen con el hilo del documento principal, pasando mensajes
- Introducción a la API de mensajería de canal
- Un ejemplo con un iframe
- Un ejemplo con un trabajador de servicios
- Soporte de navegador
Introducción a la API de mensajería de canal
Dados dos scripts que se ejecutan en el mismo documento, pero en un contexto diferente, la API de mensajería de canal les permite comunicarse pasando mensajes a través de un canal.
Este caso de uso implica la comunicación entre
- el documento y un iframe
- dos iframes
- dos documentos
Cómo funciona
Vocaciónnew MessageChannel()
se inicializa un canal de mensajes.
const channel = new MessageChannel()
El canal tiene 2 propiedades, llamadas
- puerto1
- puerto 2
Esas propiedades son un objeto MessagePort.port1
es el puerto utilizado por la parte que creó el canal, yport2
es el puerto utilizado por el receptor del canal (por cierto, el canal es bidireccional, por lo que el receptor también puede enviar mensajes).
En cada extremo del canal, escucha en un puerto y envía mensajes al otro puerto.
El envío del mensaje se realiza a través del
otherWindow.postMessage()
método, dondeotherWindow
es el otro contexto de navegación.
Acepta un mensaje, un origen y el puerto.
Por ejemplo:
const data = { name: 'Flavio' }
const channel = new MessageChannel()
window.postMessage(data, [channel.port2])
Un mensaje puede ser cualquiera de esos valores admitidos:
- Todos los tipos primitivos, excluidos los símbolos
- Matrices
- Literales de objeto
- Cuerda,Fecha,RegExpobjetos
- Gota,
File
,FileList
objetos ArrayBuffer
,ArrayBufferView
objetos- FormDataobjetos
- Objetos ImageData
- MapayColocarobjetos
"Origen" es un URI (p. Ej.https://example.org
). Puedes usar'*'
para permitir una verificación menos estricta, o especificar un dominio, o especificar'/'
para establecer un destino del mismo dominio, sin necesidad de especificar qué dominio es.
El otro contexto de navegación escucha el mensaje usando elmessage
evento:
self.addEventListener('message', event => {
console.log('A new message arrived!')
})
self
es lo mismo que usarwindow
en este caso
Dentro del controlador de eventos podemos acceder a los datos enviados mirando eldata
propiedad del objeto de evento:
self.addEventListener('message', event => {
console.log('A new message arrived!')
console.log(event.data)
})
Podemos responder usandoMessagePort.postMessage
:
self.addEventListener('message', event => {
console.log('A new message arrived!')
console.log(event.data)
const data = { someData: ‘hey’ }
event.ports[0].postMessage(data)
})
Un canal se puede cerrar invocando elclose()
método en el puerto :.
self.addEventListener('message', event => {
console.log('A new message arrived!')
console.log(event.data)
const data = { someData: ‘hey’ }
event.ports[0].postMessage(data)
event.ports[0].close()
})
Un ejemplo con un iframe
Aquí hay un ejemplo de una comunicación que ocurre entre un documento y uniframeincrustado en él.
El documento principal define uniframe
y unspan
donde imprimiremos un mensaje que se envía desde eliframe
documento. Tan pronto comoiframe
el documento está cargado, le enviamos un mensaje en elchannel
creamos.
<!DOCTYPE html>
<html>
<body>
<iframe src="iframe.html" width="500" height="500"></iframe>
<span></span>
</body>
<script>
const channel = new MessageChannel()
const display = document.querySelector('span')
const iframe = document.querySelector('iframe')
<span style="color:#a6e22e">iframe</span>.<span style="color:#a6e22e">addEventListener</span>(<span style="color:#e6db74">'load'</span>, () => {
<span style="color:#a6e22e">iframe</span>.<span style="color:#a6e22e">contentWindow</span>.<span style="color:#a6e22e">postMessage</span>(<span style="color:#e6db74">'Hey'</span>, <span style="color:#e6db74">'*'</span>, [<span style="color:#a6e22e">channel</span>.<span style="color:#a6e22e">port2</span>])
}, <span style="color:#66d9ef">false</span>)
<span style="color:#a6e22e">channel</span>.<span style="color:#a6e22e">port1</span>.<span style="color:#a6e22e">onmessage</span> <span style="color:#f92672">=</span> <span style="color:#a6e22e">event</span> => {
<span style="color:#a6e22e">display</span>.<span style="color:#a6e22e">innerHTML</span> <span style="color:#f92672">=</span> <span style="color:#a6e22e">event</span>.<span style="color:#a6e22e">data</span>
}
</script>
</html>
La fuente de la página iframe es aún más simple:
<!DOCTYPE html>
<html>
<script>
window.addEventListener('message', event => {
// send a message back
event.ports[0].postMessage('Message back from the iframe')
}, false)
</script>
</html>
Como puede ver, ni siquiera necesitamos inicializar un canal, porque elwindow.onmessage
handler se ejecuta automáticamente cuando se recibe el mensaje desde la página del contenedor.
El evento enviado está compuesto por las siguientes propiedades:
data
: el objeto que se envió desde la otra ventanaorigin
: el URI de origen de la ventana que envió el mensajesource
: el objeto de la ventana que envió el mensaje
Siempre verifique el origen del remitente del mensaje.
e.ports[0]
es la forma en que hacemos referenciaport2
en el iframe, porqueports
es una matriz y el puerto se agregó como primer elemento.
Un ejemplo con un trabajador de servicios
Un Service Worker es un trabajador impulsado por eventos, un archivo JavaScript asociado a una página web. Revisar laGuía de trabajadores de serviciospara saber más sobre ellos.
Lo que es importante saber es que los Service Workers están aislados del hilo principal y debemos comunicarnos con ellos mediante mensajes.
Así es como un script adjunto al documento principal manejará el envío de mensajes al Service Worker:
// `worker` is the service worker already instantiated
const messageChannel = new MessageChannel()
messageChannel.port1.addEventListener('message', event => {
console.log(event.data)
})
worker.postMessage(data, [messageChannel.port2])
En el código de Service Worker, agregamos un detector de eventos para elmessage
evento:
self.addEventListener('message', event => {
console.log(event.data)
})
Y puede devolver mensajes publicando un mensaje amessageChannel.port2
, con
self.addEventListener('message', event => {
event.ports[0].postMessage(data)
})
Soporte de navegador
La API de mensajería de canal es actualmente compatible con todos los navegadores principales, muchos de ellos desde hace mucho tiempo, por lo que incluso las versiones anteriores la admiten. Consulta todos los detalles enhttps://caniuse.com/#feat=channel-messaging.
Descarga mi gratisManual para principiantes de JavaScript
Más tutoriales de navegador:
- Algunos trucos útiles disponibles en HTML5
- Cómo hice que un sitio web basado en CMS funcionara sin conexión
- La guía completa de aplicaciones web progresivas
- La API de Fetch
- La guía Push API
- La API de mensajería de canal
- Tutorial para trabajadores de servicios
- La guía de la API de caché
- La guía de la API de notificaciones
- Sumérjase en IndexedDB
- La API de selectores: querySelector y querySelectorAll
- Cargue JavaScript de forma eficiente con diferir y asincrónico
- El modelo de objetos de documento (DOM)
- La API de almacenamiento web: almacenamiento local y almacenamiento de sesiones
- Descubra cómo funcionan las cookies HTTP
- La API de historia
- El formato de imagen WebP
- XMLHttpRequest (XHR)
- Un tutorial detallado de SVG
- ¿Qué son las URL de datos?
- Hoja de ruta para aprender la plataforma web
- CORS, intercambio de recursos de origen cruzado
- Trabajadores web
- La guía requestAnimationFrame ()
- Que es el Doctype
- Trabajar con la consola de DevTools y la API de la consola
- La API de síntesis de voz
- Cómo esperar el evento DOM Ready en JavaScript simple
- Cómo agregar una clase a un elemento DOM
- Cómo recorrer los elementos DOM de querySelectorAll
- Cómo eliminar una clase de un elemento DOM
- Cómo comprobar si un elemento DOM tiene una clase
- Cómo cambiar un valor de nodo DOM
- Cómo agregar un evento de clic a una lista de elementos DOM devueltos por querySelectorAll
- WebRTC, la API web en tiempo real
- Cómo obtener la posición de desplazamiento de un elemento en JavaScript
- Cómo reemplazar un elemento DOM
- Cómo aceptar solo imágenes en un campo de archivo de entrada
- ¿Por qué utilizar una versión de vista previa de un navegador?
- El objeto Blob
- El objeto de archivo
- El objeto FileReader
- El objeto FileList
- ArrayBuffer
- ArrayBufferView
- El objeto URL
- Matrices escritas
- El objeto DataView
- La API BroadcastChannel
- La API de Streams
- El objeto FormData
- El objeto del navegador
- Cómo utilizar la API de geolocalización
- Cómo utilizar getUserMedia ()
- Cómo utilizar la API de arrastrar y soltar
- Cómo trabajar con el desplazamiento en páginas web
- Manejo de formularios en JavaScript
- Eventos de teclado
- Eventos del mouse
- Toque eventos
- Cómo eliminar a todos los hijos de un elemento DOM
- Cómo crear un atributo HTML usando Vanilla Javascript
- ¿Cómo verificar si una casilla de verificación está marcada usando JavaScript?
- Cómo copiar al portapapeles usando JavaScript
- Cómo deshabilitar un botón usando JavaScript
- Cómo hacer que una página sea editable en el navegador
- Cómo obtener valores de cadena de consulta en JavaScript con URLSearchParams
- Cómo eliminar todo el CSS de una página a la vez
- Cómo utilizar insertAdjectedHTML
- Safari, avisa antes de salir
- Cómo agregar una imagen al DOM usando JavaScript
- Cómo restablecer un formulario
- Cómo utilizar las fuentes de Google