El coste de cruzar
Cuánto cuesta un invoke de verdad, dónde se va el tiempo, cómo medirlo en tu aplicación, y los tres patrones que convierten una interfaz fluida en una que se arrastra.
De qué depende
El recorrido del nivel 13.2 tiene ocho tramos, y no todos cuestan igual:
La lectura: el coste tiene un término fijo por llamada y un término proporcional al tamaño de la carga. Esa forma explica las dos estrategias que funcionan y por qué son opuestas —agrupar reduce el término fijo, y adelgazar la carga reduce el proporcional— y por qué no siempre se pueden aplicar las dos a la vez.
Medirlo en tu caso
Dos comandos y un bucle. El primero mide el término fijo:
// Un comando que no hace nada: lo que mides es el puente y solo el puente.#[tauri::command]async fn ping() {}// Y uno que devuelve una carga del tamaño que le pidas, para el otro término.#[tauri::command]async fn carga(n: usize) -> Vec<u32> { (0..n as u32).collect()}// El término fijo: muchas llamadas vacías.const t0 = performance.now();for (let i = 0; i < 1000; i++) await invoke('ping');console.log('por llamada:', (performance.now() - t0) / 1000, 'ms');// El proporcional: una llamada, cargas crecientes.for (const n of [10, 1_000, 100_000]) { const t = performance.now(); await invoke('carga', { n }); console.log(n, 'elementos:', performance.now() - t, 'ms');}Hazlo en tu máquina, en las tres plataformas si puedes, y en la versión compilada: en desarrollo hay una capa más y las cifras no son las de tu usuario. Con esos dos números tienes tu presupuesto.
Los tres patrones que lo disparan
1 · El invoke dentro de un manejador de entrada. Un campo de búsqueda que consulta al core en cada tecla, un deslizador que actualiza en cada movimiento, un lienzo que pregunta en cada fotograma. Es el más común y el más destructivo, porque el ritmo lo marca el usuario y puede ser de decenas por segundo.
La corrección: retardar la llamada hasta que el usuario pare, o limitar la frecuencia. Es la misma técnica que usarías con una API remota, por la misma razón.
2 · El invoke dentro de un bucle sobre una lista. Pintar cien filas y pedir un dato por cada una. Cien cruces donde debería haber uno.
La corrección: un comando que acepte la lista de identificadores y devuelva todos los datos de una vez. Agrupar ataca el término fijo, que es justo el que se multiplica aquí.
3 · El invoke dentro del render. Un componente que llama al core cada vez que se pinta. Con un framework reactivo, eso puede ser muchas veces por segundo y sin que nadie lo pida.
La corrección: la de siempre en la web: los datos se piden en un efecto, se guardan en el estado, y el render solo lee.
Y la corrección de fondo: invertir la dirección
Las tres correcciones de arriba son tácticas. La estratégica es otra y aparece en cuanto el problema es que el frontend pregunta demasiado:
el frontend pregunta cada segundo → n cruces por minuto, la mayoría sin cambiosel core avisa cuando algo cambia → un cruce por cambio realEse es el sistema de eventos del nivel 20, y es la respuesta correcta a una familia entera de problemas de coste: un progreso, un fichero que se está indexando, un estado que cambia por su cuenta. Si el frontend está sondeando, casi siempre es que falta un evento.
Y la corrección más radical de todas: no cruzar. Formatear una fecha, filtrar una lista que ya tienes, calcular un total de datos que ya están en el frontend — nada de eso necesita el core. El nivel 13.5 desarrolla dónde está esa línea.