Node.js por Juanda


Publicado el vie 23 marzo 2018 por Juanda
Actualizado el sáb 03 noviembre 2018 por Juanda
Categoría: desarrollo

Etiquetas: javascript v8 web multiplataforma www aplicacion software


Un producto potente trasciende su ámbito de aplicación. Y eso es lo que le ha ocurrido a Javascript con el proyecto Node.js, el cual ha sacado literalmente a Javascript del entorno del navegador y lo ha colocado al nivel del sistema operativo, permitiendo el uso de Javascript como cualquier otro lenguaje de propósito general.

Pero Node.js no es solo una máquina virtual V8 con la que ejecutar código Javascript sobre el sistema operativo. Es también un motor de ejecución que permite el desarrollo de aplicaciones concurrentes a pesar de que el motor V8 se ejecuta en un sólo hilo.

La concurrencia se consigue gracias al uso de funciones asíncronas que no bloquean la ejecución de código cuando son invocadas. Dichas funciones, en su mayoría de entrada y salida (I/O), se ejecutan en otro hilo distinto o son directamente llamadas al sistema asíncronas que una vez resueltas devuelven el resultado como el argumento de una función denominada de callback, la cual está asociada a la llamada asíncrona, y que se vuelve a colocar en la pila de llamadas (call stack) de la máquina virtual V8 para que procese el dato devuelto por la función asíncrona.

El responsable de realizar esta proeza misteriosa es un componente fundamental de Node.js denominado bucle de eventos (event loop).

Node.js usa dos tipos de hilos en su ejecución: un hilo para el bucle de eventos y varios workers. El bucle de eventos es el responsable de controlar la ejecución de las funciones callbacks y las operaciones de entrada/salida no bloqueantes, mientras que los workers ejecutan tareas correspondiente a código C++ que son bloqueantes (por eso se hacen en otro hilo, para no parar el hilo principal del bucle de eventos) y tareas de uso intensivo de la CPU.

Node.js ha sido pensado para el desarrollo de servidores siguiendo una estrategia diferente a la usada tradicionalmente. La mayor parte de los servidores ejecutan las peticiones de cada cliente en un hilo o proceso dedicado. Esta estrategia clásica presenta problemas de escalabilidad ya que el nº de hilos/procesos crece con el nº de clientes conectados al servidor. La solución propuesta por Node.js, mantiene constante el número de hilos aunque crezca el número de clientes conectados. Por eso es habitual escuchar que con Node.js se pueden realizar servidores escalables.

En su contra, hemos de decir, que si alguna de las peticiones bloquea al bucle de eventos o a los workers, la resolución de peticiones se verá degradada. Y es labor del desarrollador construir un código que evite dichos bloqueos, lo cual añade un grado de dificultad al desarrollo de servidores con Node.js respecto al modelo clásico.

A pesar de que actualmente el uso mayoritario de Node.js es el desarrollo servidores; aplicaciones web y APIs web fundamentalmente, al permitir realizar cualquier tipo de operación sobre el sistema operativo a través de las numerosas librerías que ofrece, también se está utilizando para el desarrollo de aplicaciones de consola (CLI) y de escritorio (electron).

La siguiente imagen muestra una representación de las distintas APIs y librerías que componen Node.js.
Hay que destacar el motor V8 (C++) y la librería LibUv (C++) utilizada para implementar el bucle de eventos. Además existen varias librerías de C/C++ destinadas a resolver problemas como la compresión de archivos o el manejo del protocolo SSL, una serie de añadidos en C/C++ que pueden ser fabricados por cualquier desarrollador experimentado y librerías Node.js que pueden ser desarrolladas enteramente en javascript o envolviendo el código C/C++ en funciones javascript.