Saltar al contenido

Escuchar desde el frontend

Registrar un listener, el ámbito de lo que escuchas, y la carrera que hace que un evento se pierda antes de que nadie esté oyendo. Más el caso simétrico: escuchar desde Rust.

Registrar

TypeScript
import { listen } from '@tauri-apps/api/event';const unlisten = await listen<Resumen>('catalogo-actualizado', (e) => {  pintar(e.payload);});// y más tarde, cuando ya no intereseunlisten();

Tres cosas de esas cuatro líneas:

  • Es asíncrono. Registrar un listener cruza el puente, así que hay que esperarlo. Y ese await es exactamente donde vive la carrera de más abajo.
  • Devuelve una función para desregistrar. Guardarla no es opcional: es el nivel 20.4.
  • El evento llega envuelto. El dato está en la propiedad de carga útil, junto al nombre del evento y su identificador. Es un error frecuente tratar el objeto entero como si fuera el dato.

Los dos ámbitos

La confusión típica: emitir a una ventana concreta y escuchar globalmente en otra. El evento no llega, y no hay error. Es la primera hipótesis a comprobar cuando algo no se recibe, junto con las cuatro del nivel 20.1.

La carrera del arranque

Es la trampa que cuesta descubrir. Recuerda el nivel 4.2: el core y la webview arrancan en paralelo. Si el core emite un evento durante su inicialización —o justo después— el frontend puede no haber registrado todavía su listener, y ese evento se pierde para siempre.

TXT
core:      setup ──▶ emit("listo") ──▶ …webview:      cargar HTML ──▶ ejecutar JS ──▶ await listen("listo")                                              └─ demasiado tarde

Tres soluciones, y la tercera es la buena:

Registrar antes que nada. Poner los listeners en lo primero que ejecuta el frontend, antes de pintar. Reduce el hueco y no lo cierra: el hueco existe desde que el core arranca.

Que el core espere. Emitir solo después de que el frontend avise de que está listo, con un comando. Funciona y añade un viaje y un estado más.

Que el estado sea consultable, no solo emitido. Es la buena, y es un principio general: por cada evento importante, un comando que devuelve el estado actual. El frontend, al arrancar, pregunta una vez y se suscribe; a partir de ahí vive de los eventos.

TypeScript
// el patrón que cierra la carreraconst unlisten = await listen('sincronizacion-estado', (e) => pintar(e.payload));pintar(await commands.estadoSincronizacion());   // y ahora el estado de partida

El orden importa: primero suscribirse y después preguntar. Al revés, un cambio ocurrido entre las dos líneas se pierde igual.

Escuchar desde Rust

El canal funciona en los dos sentidos, y el core también puede escuchar:

Rust
app.listen("frontend-listo", |evento| {    println!("el frontend dice: {:?}", evento.payload());});

Sirve para dos cosas concretas: que el frontend avise de algo sin esperar respuesta —donde un comando sería más ceremonia de la necesaria— y que una parte del core se entere de lo que hace otra sin acoplarlas.

Y una advertencia: para que el frontend emita hace falta permiso, igual que para escuchar. Conceder la emisión desde el frontend amplía la superficie —cualquier código en la webview puede emitir cualquier evento, incluidos los que tu propio core escucha— así que conviene concederlo solo si de verdad se usa.