¿Qué es WebAssembly ?

El desarrollo Web ha tenido una interesante historia, digamos que muchos intentos han sido hechos  para expandir la plataforma y para soportar diferentes lenguajes. Las soluciones anticuadas, como los complementos (plugins), no resistieron la prueba del tiempo y limitar a un usuario a un único navegador es una receta que no sirve.

WebAssembly fue desarrollado como una solución elegante para un problema que ha existido desde que los navegadores pudieron  ejecutar código por primera vez.  Si deseamos desarrollar para la web, debemos usar JavaScript. Afortunadamente, usando JavaScript no tenemos los mismos problemas negativos que teníamos cuando comenzaba este siglo, pero continua teniendo algunas limitaciones como lenguaje de programación. En este post vamos a ver que tecnologías conducen a WebAssemby para ser una nueva alternativa al desarrollo web. Comencemos viendo como fue la evolución de JavaScript. 

La evolución de JavaScript

JavaScript fue creado por Brendan Eich en solo 10 días haya por el año 1995. Para lo primero que fue utilizado fue para crear botones o banners que aparecían en las páginas webs. Pero en la última década JavaScript se ha convertido en una plataforma con mas capacidades y un masivo seguimiento de los desarrolladores.

En 2008, la fuerte competencia en el mercado de los navegadores resultó en la adición de compiladores JIT (Just in time), que aumentaron la velocidad de ejecución de JavaScript en un factor de 10. Node.js salió en 2009 y esto representó un cambio de paradigma en el desarrollo web. Ryan Dahl (creador de Node.js) combinó el motor de JavaScript V8 de Google, un bucle de eventos y una API de E/S de bajo nivel para construir una plataforma que permitiera el uso de JavaScript como servidor del lado del cliente. Luego Node.js condujo a npm, un administrador de paquetes que permitió el desarrollo de bibliotecas para ser utilizadas dentro del ecosistema Node.js. Se han desarrollado cientos de miles de paquetes y todos los días son agregados más.

Por otro lado, no es solo el ecosistema de Node.Js que esta creciendo, JavaScript por si mismo también esta siendo activamente desarrollado. LA ECMA Technical Committee 39 (TC39), la cual dicta los estándares para JavaScript y supervisa la adición de nuevas características del lenguaje, publica actualizaciones anuales de JavaScript con un proceso de propuesta impulsado por la comunidad.

Pero lamentablemente el lenguaje tiene algunas deficiencias:

  •  Hasta hace poco, JavaScript solo incluía números de punto flotante de 64 bits. Esto puede causar problemas con números muy grandes o muy pequeños. BigInt, una nueva definición de número que puede alivianar algunos de estos problemas, se encuentra en proceso de agregarse a la especificación ECMAScript, pero puede llevar algún tiempo hasta que sea totalmente compatible con los navegadores.
  • JavaScript no es tan eficaz como los idiomas compilados a pesar de los mejores esfuerzos de los proveedores de navegadores.
  • Si un desarrollador desea crear una aplicación web, necesita aprender JavaScript, le guste o no.

Para evitar tener que escribir muchas líneas de código para desarrollar alguna funcionalidad compleja, algunos desarrolladores construyeron transpiladores (transpilers) para convertir otros lenguajes a JavaScript. Los transpiladores (o compiladores de código a código) son tipos de compiladores que convierten el código fuente en un lenguaje de programación en un código fuente equivalente en otro lenguaje de programación. TypeScript, que es una herramienta popular para el desarrollo de JavaScript para el frontend, transpila TypeScript a JavaScript válido para navegadores. Si elegimos cualquier lenguaje de programación, es muy probable que alguien haya creado un transpiler de JavaScript para el. Por ejemplo, si prefiere escribir Python, tiene aproximadamente 15 herramientas diferentes que puede usar para generar JavaScript. Sin embargo, al final, aún es JavaScript, por lo que aún estamos sujeto a lo que dicta este lenguaje. A medida que la web se convirtió en un plataforma válida para crear y distribuir aplicaciones, se crearon aplicaciones cada vez más complejas y con un uso intensivo de recursos. Para satisfacer las demandas de estas aplicaciones, los proveedores de navegadores comenzaron a trabajar en nuevas tecnologías para integrarlo en su software sin interrumpir el curso normal del desarrollo web. Google y Mozilla, creadores de Chrome y Firefox, respectivamente, tomaron dos caminos diferentes para lograr este objetivo, culminando en la creación de WebAssembly.

Google y el Cliente Nativo (Native Client)

Google desarrollo Native Client (NaCI) con el intento de correr código nativo dentro del navegador. El código ejecutable podría corren en un “sandbox” y ofrecer las ventajas de performance de la ejecución de un código nativo.

Aclaración: Sandbox en el contexto de desarrollo de software es un entorno que evita que el código ejecutable interactue con otras partes de su sistema. Es básicamente para establecer restricciones sobre lo que puede hacer el software.

NaCI (native cliente) fue ajustado a una arquitectura específica, mientras que Portable Native Client (PNaCI) era una versión de NaCI independiente de la arquitectura desarrollada para ejecutarse en cualquier plataforma. La tecnología consistía en dos elementos básicos:

  • Un conjunto de herramientas que podrían transformar el código C/C++ en módulos NaCI.
  • Componentes de tiempo de ejecución que eran componentes incrustados en el navegador que permitían la ejecución de módulos NaCI.

Bien, entonces el ejecutable específico de la arquitectura NaCI’s (nexe) fue limitado a aplicaciones y extensiones que fueran instaladas desde el Store de Google Chrome, pero por otro lado los ejecutables de PNaCI (pexe) podían ser libremente distribuidos en la web y ser incluidos en las aplicaciones web. Esta portabilidad, fue gracias a Pepper, una API open source para crear modulos NaCI, y su correspondiente plugin API(PPAPI). Pepper permitió la comunicación entre los módulos de NaCI y el navegador que lo alojaba, y permitió el accesso a las funciones a nivel de sistema en una forma segura y portable. Las aplicaciones podían ser fácilmente distribuidas incluyendo un archivo de manifiesto y un modulo compilado (pexe) con el HTML, CSS y JavaScript correspondientes.

NaCI ofreció oportunidades que parecían prometedoras para superar las limitaciones de rendimiento de la Web, pero tenía algunos inconvenientes. Aunque Chrome tenía soporte incorporado para los ejecutables PNaCI y Pepper, otros navegadores no lo tenían. Muchos estuvieron en desacuerdo con la naturaleza de caja negra de estas aplicaciones, así como con los riesgos y la complejidad portenciales de la seguridad.

Mozilla por sus parte, centró esfuerzos en mejorar el rendimiento de JavaScript con asm.js. No iban a agregar soporte para Pepper a Firefox debido a que existía una incompleta especificación de la API y la documentación que existía era limitada. Al final, NaCI quedó en desuso en mayo de 2017, a favor de WebAssembly.

Mozilla y asm.js

Mozilla saco a luz asm.js en 2013 y les proporciono a los desarrolladores una forma de traducir su código fuente C y C++ a JavaScript. La especificación oficial para asm.js lo define esto como un subconjunto estricto de JavaScript y que se puede usar como un lenguaje de bajo nivel eficiente para los compiladores. Sobre esa base se implementa en el navegador, un mecanismo que se denomina AOT(Ahead of Time). AOT es una técnica que el motor de JavaScript del navegador utiliza para ejecutar el código de manera más eficiente al compilarlo en un código de máquina nativo. Podríamos decir, que directamente toma el JavaScript y lo convierte a ensamblador, por eso el nombre asm.js.  El archivo asm.js logra estas mejoras de rendimiento al tener un 100% de consistencia de tipos y administración de memoria manual.

Usando una herramietna com Emscripten (compilador de código a código y generador asm.js), el código C/C++ puede ser transpilado a asm.js y fácilmente distribuido usando los mismos medios que usamos para el JavaScript normal.  El acceso a las funciones en un módulo asm.js require vinculación, lo que implica llamar a su función para obtener un objeto con las exportaciones del módulo.

asm.js es flexible, sin embargo, ciertas interacciones con el módulo puede causar una pérdida de rendimiento. Por ejemplo, si un módulo de asm.js se le da accesso a una función de JavaScript personalizada que falla con la validación dinámica o estática, el código no puede aprovechar AOT y recurre al intérprete

El Sitio oficial de WebAssembly menciona asm.js en la sección titulada metas de alto nivel de WebAssembly. Entonces, la pregunta que se nos ocurriría aquí seria, ¿ por qué usar WebAssembly cuando prodríamos  usar asm.js. ? Aparte de la posible pérdida de rendimiento, un módulo asm.js es un archivo de texto que debe transferirse a través de la red antes que se lleve a cabo cualquier compilación. Un módulo WebAssembly es un formato binario, lo que lo hace mucho más eficiente para transferir debido a su tamaño más pequeño.

WebAssembly sale a luz

La World Wide Web Consortium (W3C), una comunidad internacional creada para desarrollar los estandares para la web, formo el grupo de trabajo de WebAssembly en abril 2015 para estandarizar WebAssembly y supervisar el proceso de especificación y propuesta. Desde entonces, la especificación principal y la API de JavaScript y la API web correspondientes se han publicado. La implementación inicial del soporte de WebAssembly en los navegadores se basó en el conjunto de características de asm.js. El formato binario de WebAssembly y el archivo correspondiente .wasm combinaron facetas de la salida de asm.js con el concepto de PNaCI en un ejecutable binario.

Entonces, ¿ cómo será el éxito de WebAssembly donde falló NaCI ? De Acuerdo con el Dr. Axel Rauschmayer, hay tres razones detalladas en Tres Razones por la cual WebAssembly será exitoso 

  1. Este es un esfuerzo de colaboración, ninguna compañía lo hace sola. Por el momento, están involucrados los siguientes proyectos: Firefox, Chromium, Edge y WebKit.
  2. La interoperabilidad con la plataforma web desde JavaScript será tan simple como importar un módulo.
  3. No se trata de reemplazar los motores de JavaScript, se trata más bien de agregarles una nueva función. Eso reduce considerablemente la cantidad de trabajo para implementar WebAssembly y debería ayudar a obtener el soporte de la comunidad de desarrollo web.

¿Qué es exactamente  WebAssembly y donde puedo Usarlo ?

WebAssembly tiene una definición descriptiva en el sitio oficial, pero es solo una pieza del rompecabezas. Hay varios otros componentes que caen bajo el paraguas de WebAssembly.

Definición Oficial

El sitio web oficial de WebAssembly (Sitio Oficial de WebAssembly) ofrece esta definición:

Wasm es un formato de instrucciones binario para una máquina virtual basada en una pila (stack). Wasm esta diseñado como un destino portátil para la compilación de lenguajes de alto nivel como C/ C++/ Rust, permitiendo la implementación en la web para aplicaciones de cliente y servidor.

Veamos como podemos separar esta definición en partes para poder clarificarla un poco mas.

Formato de instrucción binario:

WebAssembly en realidad abarca varios elementos: un formato binario y un formato de texto, que se documentan en la especificación del núcleo  y las API correspondientes (JavaScript y web). Tanto el formato binario como el de texto se asignan a una estructura común en forma de sintaxis abstracta. Para comprender mejor la sintaxis abstracta, se puede explicar en el contexto de un árbol de sintaxis abstracta (AST = abstract syntax tree). Un AST es una representación de árbol de la estructura del código fuente para un lenguaje de programación. Herramientas como ESLint utilizan AST de JavaScript para encontrar errores de tabulación. Debajo veremos un ejemplo que contiene una función y el AST correspondiente para JavaScript (el ejemplo fue tomado de astexplorer.net)

Veamos una simple función en JavaScript:

 

El correspondiente AST de esta función es como sigue:

Un AST puede ser muy detallado, pero hace un excelente trabajo al describir los componentes de un programa. La representación del código fuente en un AST hace que la verificación y la compilación sean simples y eficientes. El código WebAssembly en formato texto se serealiza en AST y se compila en formato binario (como un archivo .wasm), que se obtiene, se carga y se utiliza en una página web. Cuando el módulo es cargado, el motor de JavaScript del navegador utiliza una pila de decodificación para decodificar el archivo .wasm en un AST, realizar una comprobación de tipo e intepretarlo para ejecutar funciones. WebAssembly comenzó como un formato de instrucciones binarias para un AST. Debido a las implicancias de rendimiento de esta verificación de las expresiones wasm que devuelven void , el formato de instrucciones binarias se actualizó para apuntar a una máquina de pila (stack machine). Una stack machine consta de dos elementos: una pila y las instrucciones. Una pila es una estructura de datos con dos operaciones: push y pop. Los elementos se insertan en la pila y, posteriormente, se extraen de la pila en el orden de último en entrar, primero en salir (LIFO). Una pila también incluye un puntero, que apunta al elemento de la parte superior de la pila. Las instrucciones representan acciones para realizar en los elementos de la pila. Por ejemplo, una instrucción ADD puede sacar los dos elementos superiores de la pila (los valores 100 y 10), y pushear un solo elemento con la suma del nuevo en la pila (el valor 110).

 

Portable para la compilación

WebAssembly se diseñó desde el principio teniendo en cuenta la portabilidad. La portabilidad en este contexto significaría que el formato binario de WebAssembly se puede ejecutar de manera eficiente en una variedad de sistemas operativos, dentro y fuera de la web. La especificación para WebAssembly define la portabilidad en el contexto de un entorno de ejecución. WebAssembly fue diseñado para ejecutarse eficientemente en entornos que cumplen con ciertas características, la mayoría de las cuales están relacionadas con la memoria. La portabilidad de WebAssembly también puede atribuirse a la ausencia de una API específica.

Esto significa que WebAssembly no está vinculado a un entorno específico, como lo sería la web o el escritorio. El grupo de trabajo que se ha formado para definir los estandares de WebAssembly ha definido una API web, pero eso está separado de la especificación del núcleo en si. La definición indica que WebAssembly será fácil de compilar en un formato binario a partir del código fuente escrito en lenguajes de alto nivel.

La especificación del núcleo de WebAssembly se codifica en un lenguaje de programación  de bajo nivel, similar a un ensamblaje. Esta especificación define la estructura , ejecución y validación de este lenguaje, asi como los detalles de los formatos binarios y de texto. Este lenguaje esta estructurado en torno a los siguientes conceptos:

  • Valores: tipo de valores que proporciona WebAssembly.
  • Instrucciones: son ejecutadas dentro de  la stack machine.
  • Trampas (Traps): son producidas en condiciones de error
  • Funciones: En las cuales se organiza el código, cada uno de los cuales toma una secuencia de valores como parámetros y devuelve una secuencia de valores como resultado.
  • Tablas: Son matrices de valores de un tipo de elemento particular (como las referencias a funciones) que el programa que se esta ejecutando selecciona.
  • Memoria Lineal: es una matriz de bytes sin procesar que se puede usar para almacenar y cargar valores.
  • Modulos: Es el WebAssembly en formato binario (archivo .wasm) que contiene funciones, tablas y memorias lineales.
  • Embedder: el mecanismo por el cual WebAssembly se puede ejecutar en un entorno host, como un navegador.

Las funciones, tablas, memoria lineal y módulos tienen correlaciones directas con las API de JavaScript y son importantes a tener en cuenta. Estos conceptos describen la estructura del lenguaje en si y como escribir o codificar WebAssembly.

Fases semánticas

La especificación del núcleo describe las diferentes fases que experimenta un módulo codificado (archivo .wasm) cuando se utiliza en un entorno host (como lo es un navegador web). Esta especificación representa cómo se maneja y ejecuta la salida. Estas son las diferentes fases:

  • Decodificación: El formato binario se convierte en un módulo.
  • Validación: el módulo descodificado se somete a verificaciones de validación (como por ejemplo la verificación de tipo) para garantizar el formato del módulo.
  • Ejecución, Parte 1 (Instanciación): Creación de instancias: una instancia de módulo, la cual es la representación dinámica del módulo, es instanciada para la inicialización de variables globales, memorias y tablas, e invoca a la función Start() del módulo.
  • Ejecución Parte 2: (Invocación): Las funciones exportadas se llaman desde la instancia del módulo.

JavaScript y las Web APIs

El grupo encargado de las definiciones de los estándares de WebAssembly ha establecido las especificaciones de la API para interactuar con JavaScript en la web,  lo cual define su inclusión en el espacio de la tecnología de WebAssembly. La API de JavaScript esta orientada al lenguaje JavaScript en si, sin estar específicamente vinculada a un entorno (por ejemplo, navegadores web o por ejemplo Node.JS). Estos estandares define clases, métodos y objetos para interactuar con WebAssembly y administrar los proceses de compilación  y creación de instancias.

¿WebAssembly remplazará a JavaScript ?

Es una pregunta que nos podríamos hacer al ver la definiciones de WebAssembly. Pero el objetivo final de WebAssembly no es remplazar JavaScript, sino complementarlo. Todo el ecosistema y la flexibilidad de JavaScript aún lo convierten en el lenguaje ideal para la web. La API de JavaScript de WebAssembly hace que la interoperabilidad entre las dos tecnologías sera relativamente simple. Entonces, ahora la pregunta es,¿se podrá construir una aplicación web utilizando solo WebAssembly ? Uno de los objetivos explícitos de WebAssembly es la portabilidad, y replicar toda la funcionalidad de JavaScript podría inhibir ese objetivo. Puede ser que no sea práctico escribir todo el código base en un lenguaje que compile en WebAssembly, pero mover parte de la lógica de la aplicación a los módulos wasm podría ser beneficioso en términos de rendimiento y tiempos de carga.

¿Donde  podemos usar WebAssembly ?

El sitio oficial de WebAssembly tiene una lista extensa de posibles casos de uso de esta tecnología:

  • Edición de imagen y video
  • Juegos
  • Aplicaciones de música (streaming)
  • Reconocimiento de imagen
  • VR, realidad aumentada.

Aunque algunos de estos ejemplos son técnicamente factibles con JavaScript, HTML y CSS, el uso de WebAssembly puede ofrecer ganancias significativas de rendimiento. La publicación de un archivo binario (en lugar de archivos JavaScript) puede reducir en gran medida el tamaño del paquete, y al crear una instancia del módulo wasm  la ejecución del código acelera la  carga de la página.

WebAssembly no se limita al navegador. Fuera del navegador, podemos usarlo para crear aplicaciones híbridas nativas en dispositivos móviles o realizar cálculo del lado del servidor. El uso de módulos wasm para aplicaciones de celulares podría ser beneficioso en términos de uso de energía y rendimiento.

WebAssembly también ofrece flexibilidad con respecto a cómo se puede utilizar . Podemos escribir todo nuestro código en WebAssembly, aunque esto puede no ser práctico en el contexto de una aplicación web. Dada lo robusto de la API de JavaScript de WebAssembly, podemos escribir nuestra UI (interfaz de usuario) en JavaScript y HTML y usar los módulos wasm para funcionalidades que no acceden directamente al DOM.

Qué lenguajes son soportados ?

Los primeros lenguajes que soporto WebAssembly fueron C, C++ y Rust. Luego existen varias herramientas para permitir el uso de WebAssembly con algunos de los otros lenguajes de programación populares, aunque en su mayoría son experimentales:

  • C # a través de Blazor
  • Haxe a través de WebIDL
  • Java a través de TeaVM o Bytecoder
  • Kotlin via TeaVM
  • TypeScript a través de AssemblyScript

Cuáles son las limitaciones ?

Es cierto que, WebAssembly no está exenta de limitaciones, pero se están desarrollando activamente nuevas funciones y la tecnología esta en constante evolución. Algunas de las limitaciones de WebAssembly son:

No soporta Garbage CollectionWebAssembly es compatible con una memoria lineal plana, que no es una limitación en sí misma, pero requiere cierta comprensión de cómo asignar explícitamente la memoria para ejecutar el código. Lenguajes como C y C ++  la memoria está integrada en el lenguaje.

No soporta acceso directo al DOM: WebAssembly no puede acceder al DOM, por lo que cualquier manipulación del DOM debe realizarse indirectamente a través de JavaScript o mediante una herramienta como Emscripten. Hay planes para agregar la capacidad de referenciar al DOM y otros objetos de la API web directamente, pero eso todavía está en la fase de propuesta.

No soportado en los navegadores viejos: Los navegadores más antiguos no tienen el objeto WebAssembly global disponible para crear instancias y cargar módulos wasm. Puede ver qué navegadores soportan actualmente WebAssembly en https://caniuse.com/#search=webassembly 

Bien hasta aquí una introducción a WebAssembly y sus principales características. Esta tecnología puede ser en un futuro cercano muy beneficiosa en cuanto a rendimiento y  aceleración de carga de páginas web. En próximas entradas, veremos como configurar un entorno de programación para esta tecnología. Si desean comentar, pueden dejar su comentario aquí debajo. Saludos !!!

The following two tabs change content below.
Admin

Admin

Administrador de Dotnetuy, con más de 20 años de experiencia en el mundo de la informática y el desarrollo de software en diferentes lenguajes, trabajando en backend y frontend, desde sus primeros pasos con clipper cuando comenzaba la década de los 90’s , y continuando con pascal, C, C++, Visual basic, y multiples gestores de bases de datos hasta hoy en día con C# y todas las técnologias relacionadas con .NET.

2 thoughts on “¿Qué es WebAssembly ?

  1. Hola Gonzalo,

    Agradecemos mucho tu comentario, y nos alegra mucho que fuera de utilidad. Quedamos a las órdenes por cualquier consulta.

    Saludos

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *