Node.js es una plataforma de software con una arquitectura basada en eventos que permite utilizar JavaScript, originariamente desarrollado para su uso del lado del cliente, en el lado del servidor, de la misma forma como se usan PHP, Java, .NET, Ruby o Python para escribir código en el servidor. Suele usarse para el desarrollo de aplicaciones JavaScript del lado del servidor que han de procesar grandes volúmenes de datos en tiempo real y es muy popular en la realización de servidores web ligeros.
Este proyecto de software multiplataforma nace en 2009 de la mano del desarrollador Ryan Dahl y está basado en el motor JavaScript de Google V8, utilizado en el navegador Chrome. Patrocinado por la empresa Joyent Inc, especializada en virtualización y computación en la nube, y desarrollado por la Node.js Foundation, Node.js está hoy sujeto al programa de proyectos colaborativos de la Linux Foundation. Las versiones actuales están disponibles para Microsoft Windows, Mac OS y Linux (la versión inicial solo soportaba Linux).
Node.js contiene una biblioteca de módulos de JavaScript que se pueden cargar con una función muy sencilla y que están disponibles como piezas prediseñadas para su uso en el desarrollo de aplicaciones web. Un ejemplo de ellos es el módulo “http”, que permite crear un servidor web rudimentario utilizando una sola función. La instalación posterior de módulos adicionales también es posible gracias al gestor de paquetes integrado NPM (Node Package Manager).
La mayor ventaja de Node.js es su arquitectura dirigida por eventos, con la cual se pueden ejecutar códigos de forma asíncrona. Para ello se apoya en hilos de ejecución independientes y en un sistema de entrada y salida de datos (Input/Output, o simplemente I/O) separada que permite el procesamiento paralelo de más de una operación de escritura o lectura.
- I/O asíncrono: entre las tareas clásicas de un servidor se cuentan responder (servir) a peticiones, almacenar información en una base de datos, leer archivos en el disco duro y establecer conexiones con otros componentes de la red, acciones que se agrupan bajo la abreviatura I/O del inglés “input” (entrada) y “output” (salida). En lenguajes de programación como C o Java las operaciones I/O se ejecutan de forma sincrónica, es decir, una tras otra. Esto hace que el sistema I/O permanezca bloqueado hasta que el proceso actual finalice. Por el contrario, Node.js utiliza un I/O asíncrono por el cual las operaciones de escritura y de lectura se delegan directamente en el sistema operativo o a una base de datos, lo que permite ejecutar un gran número de tareas I/O en paralelo sin que se llegue a un bloqueo (blocking). Esto proporciona una enorme velocidad a las aplicaciones basadas en Node.js y JavaScript en muchos escenarios, aventajando a otros sistemas.
- Hilos de ejecución (single threading): para compensar los tiempos de espera propios de un sistema I/O sincrónico, aquellas aplicaciones del servidor basadas en lenguajes de programación clásicos del lado del servidor se apoyan en hilos de ejecución o subprocesos, aun con los mencionados inconvenientes de este concepto. Un servidor Apache HTTP, por ejemplo, inicia para cada petición entrante un nuevo hilo. La cantidad de hilos procesables, y, con ella, el número de peticiones que pueden responderse de forma paralela en un sistema multihilo síncrono, viene definida por la capacidad de almacenamiento disponible. Node.js, por el contrario, al utilizar un I/O asíncrono, solo necesita un hilo, de forma que se reducen de forma considerable tanto la complejidad como la carga sobre los recursos.
- Arquitectura basada en eventos: es la que permite el procesamiento asíncrono de operaciones I/O. Se basa esencialmente en un único hilo de ejecución que se encuentra en una cinta continua de acontecimientos, cuya tarea es esperar a que se produzcan sucesos y gestionarlos. Estos se pueden presentar como tareas o como resoluciones. Cuando este bucle de eventos registra una tarea, una petición a la base de datos, por ejemplo, la delega mediante una función llamada “callback” a un proceso en un segundo plano. De esta forma, esta tarea no se procesa en el mismo hilo del bucle de eventos y este puede esperar al próximo suceso. Cuando un proceso en el segundo plano finaliza, la resolución se devuelve con la función “callback” al bucle de eventos, que puede resolver la entrega del resultado.
Este modelo no bloqueador dirigido por eventos tiene la ventaja de que una aplicación no permanezca inactiva mientras espera a que se produzcan eventos. Esto permite, por ejemplo, que puedan ejecutarse varias peticiones a la base de datos al mismo tiempo sin afectar al funcionamiento del programa. Es así como Node.js se convierte en la mejor herramienta para realizar arquitecturas web que requieran diversas peticiones externas, aventajando así al procesamiento síncrono.