Gracias a WebAssembly podemos ejecutar código de otros lenguajes de programación desde el navegador web con JavaScript. La ventaja de WASM es que, aparte de ser rápido, permite programar en otro lenguaje y aprovechar las librerías presentes en el mismo.
Personalmente he usado Golang con WebAssembly para crear un generador de credenciales, códigos QR y códigos de barras. Todo el procesamiento y generación de imágenes se hace con Go, para luego exportar los resultados a JavaScript.
En este post voy a documentar cómo exportar un arreglo de tipo byte ([]byte) de Go a un Uint8Array de JavaScript, ya que, como te lo dije anteriormente, esto sirve cuando creamos un archivo binario con Go y queremos exportarlo a JavaScript.
Además, un Uint8Array
sí puede ser transportado a través de un WebWorker usando el structured clone algorithm.
Yo expongo la función así:
js.Global().Set("generarCodigos", js.FuncOf(GenerarCodigos))
Aquí Global()
va a devolver el ámbito global desde donde se invoca a la función de WASM.
Si estamos en un WebWorker será self, si estamos en el DOM será window y puede devolver otra cosa según el entorno.
Fíjate en que la estoy exponiendo como generarCodigos
así que podré invocarla desde JavaScript con self.generarCodigos()
, y que realmente la función de Go se llama GenerarCodigos
cuyo código dejo a continuación:
func GenerarCodigos(this js.Value, parametros []js.Value) interface{} {
bytesQueConformanElPDF, err := crearPdfConCodigosQr()
if err != nil {
return false
}
destinoBytesPDFEnJS := js.Global().Get("Uint8Array").New(len(bytesQueConformanElPDF))
arreglo := parametros[0]
longitudArreglo := arreglo.Get("length").Int()
log.Printf("El arreglo mide %#v", longitudArreglo)
for indice := 0; indice < longitudArreglo; indice++ {
objeto := arreglo.Index(indice)
nombre := objeto.Get("nombre").String()
existencia := objeto.Get("existencia").Float()
log.Printf("Nombre %#v existencia %#v", nombre, existencia)
}
js.CopyBytesToJS(destinoBytesPDFEnJS, bytesQueConformanElPDF)
return destinoBytesPDFEnJS
}
Realmente el cuerpo de la función no es relevante. Solo estoy probando si estoy recibiendo correctamente el arreglo de objetos desde JavaScript. La parte importante viene a continuación:
Tengo el siguiente arreglo de bytes que representan un PDF:
bytesQueConformanElPDF, err := crearPdfConCodigosQr()
if err != nil {
return false
}
Lo importante es que bytesQueConformanElPDF
es un []byte
.
Ahora vamos a copiar el arreglo de bytes a JavaScript para devolverlo como resultado de la invocación. Hacemos un nuevo Uint8Array
cuya longitud será la misma que la longitud del arreglo que tenemos en Go y que podemos obtener con len
:
destinoBytesPDFEnJS := js.Global().Get("Uint8Array").New(len(bytesQueConformanElPDF))
Ese fragmento de código es el equivalente a new Uint8Array()
de JavaScript. Luego invocamos a js.CopyBytesToJS
indicando el destino y el origen. El destino será el Uint8Array
que definimos desde Go usando New
, y el origen será el []byte
que tenemos en Go, así:
js.CopyBytesToJS(destinoBytesPDFEnJS, bytesQueConformanElPDF)
Y ahora vamos a tener ese Uint8Array como resultado de la invocación de la función. En mi caso lo tengo con Comlink y un worker expuestos a través de una Store de Vue, así que lo uso así:
const generar = async () => {
const resultado = await dbStore.testing([
{ nombre: "Prueba", existencia: 3 },
{ nombre: "Otra cosa", existencia: 3 },
{ nombre: "Tercer elemento", existencia: 3 },
]);
const blob = new Blob([resultado], { type: "application/pdf" });
const enlace = document.createElement('a');
const url = URL.createObjectURL(blob);
enlace.href = url;
enlace.download = "desde_js.pdf";
enlace.click();
URL.revokeObjectURL(url);
console.log("El resultado es %o", resultado);
}
Aquí, resultado
es el Uint8Array que devolvió la invocación a WebAssembly. En el ejemplo lo estoy descargando pero podemos hacer más cosas.
Así de simple podemos invocar a una función de Go desde JavaScript pasando y recibiendo parámetros complejos, ya que invocamos a la función con un arreglo de objetos que podemos leer en Go, y luego Go nos devuelve un Uint8Array.
Nota importante: aunque aquí uso “Go” y “JavaScript” como si se ejecutaran en entornos separados la verdad es que ambos se van a ejecutar en el navegador web gracias a WebAssembly.
Revisando y buscando maneras de imprimir un PDF desde la línea de comandos me encontré…
Esta semana estuve recreando la API del plugin para impresoras térmicas en Android (HTTP a…
Hoy te enseñaré a extraer la cadena base64 de una clave PEM usando una función…
Encender un foco con un Bot de Telegram es posible usando una tarjeta como la…
El día de hoy te mostraré cómo crear un servidor HTTP (servidor web) en Android…
En este post te voy a enseñar a designar una carpeta para imprimir todos los…
Esta web usa cookies.