Nyx compilado a wasm32-wasi puede usar await de verdad: una async fn que llama a await browser_fetch_await(...) ESPERA la respuesta del servidor y sigue en la línea siguiente con el valor, sin partir el flujo en un cierre por cada pedido. El módulo nuevo std/browser_await vive aparte de std/browser a propósito: solo paga el costo de Asyncify (más binaryen como dependencia de build) el programa que lo importa.
// 109 — await en el navegador: una pantalla que carga una factura sin callbacks // // Target wasm32-wasi (corre en el navegador, o bajo node con // examples/browser/run-node.mjs). `await browser_fetch_await(...)` ESPERA la // respuesta del servidor y la función sigue en la línea siguiente con el // valor: sin partir el flujo en un cierre por cada pedido. // // Construir: nyx build --target wasm32-wasi // (necesita binaryen: `sudo apt install binaryen`, o NYX_WASM_OPT=/ruta/a/wasm-opt; // nyx build lo usa SOLO porque el programa espera al anfitrión) // // Lo que conviene saber: // - El status HTTP no es error: un 404 llega como Ok con r.status == 404. // Err es «no hubo respuesta» (kind "connection") o «venció el plazo» ("timeout"). // - UNA sola función puede estar esperando a la vez. Un click que llega // durante el fetch se procesa cuando el fetch termina, en orden. // - spawn y los canales siguen sin existir en wasm: await es secuencial. import "std/browser_await" import "std/dom" import "std/error" async fn cargar_factura(id: int) -> String { let res = await browser_fetch_await_opts("/api/facturas/" + int_to_string(id), "GET", "", 5000) match res { Result.Ok(r) => { if r.status != 200 { return "la factura " + int_to_string(id) + " no está (HTTP " + int_to_string(r.status) + ")" } return r.body } Result.Err(e) => { return "sin respuesta del servidor: " + e.kind + " (" + e.msg + ")" } } } // El botón «abrir» de cada fila llama a este export con el número de factura. #[export_name = "abrir_factura"] fn abrir_factura(id: int) { dom_set_text("#estado", "cargando la factura " + int_to_string(id) + "...") let texto: String = await cargar_factura(id) dom_set_text("#factura", texto) dom_set_text("#estado", "listo") } fn main() { abrir_factura(7) }
#estado → "cargando la factura 7..." #factura → (el cuerpo de la respuesta, o el motivo del fallo) #estado → "listo"
Cómo funciona
El status HTTP no es un error: un 404 llega como Result.Ok con r.status == 404, y cargar_factura lo distingue a mano. Lo único que cae en Result.Err es no haber tenido respuesta —kind "connection" o "timeout"—, el mismo vocabulario de Error que el resto de la stdlib.
abrir_factura es el export que llama el botón «abrir» de cada fila: actualiza el DOM antes de esperar, espera con await, y actualiza el DOM otra vez con el resultado — sin un callback de por medio. Solo puede haber UNA función esperando a la vez: un click que llega durante el fetch se procesa recién cuando el fetch termina, en orden.
Construir necesita binaryen (wasm-opt) porque el .ll generado trae un marcador de imports Asyncify; un programa sin #[suspends] compila byte a byte igual que antes. spawn y los canales siguen sin existir en wasm: acá await es secuencial.