13 pilares de Node.js

¿Qué hay detrás de Node.js?

Node.js permite ejecutar JavaScript fuera del navegador y se utiliza con frecuencia para construir servidores, APIs, herramientas de línea de comandos y otros programas que requieren operaciones de entrada y salida.

Para entender cómo funciona, conviene separar varios conceptos que trabajan juntos. Estos son trece pilares que ayudan a construir una visión general de Node.js.

1. JavaScript en el servidor

Node.js permite ejecutar JavaScript en el lado del servidor mediante un entorno basado en el motor V8.

Esto permite utilizar JavaScript para construir programas que no dependen de un navegador para ejecutarse.

JavaScript
   ->
Node.js
   ->
Servidor / API / Aplicación

2. Event Loop

El Event Loop coordina muchas de las operaciones asíncronas de Node.js.

Node.js puede continuar ejecutando código mientras determinadas operaciones de entrada y salida esperan su resultado. Cuando una operación termina, su continuación puede entrar en el flujo de ejecución correspondiente.

Código
  ->
Operación asíncrona
  ->
Event Loop
  ->
Callback / Promise / Evento

3. Programación asíncrona

Node.js utiliza distintos mecanismos para manejar operaciones que no necesitan bloquear el flujo principal mientras esperan una respuesta.

Entre ellos están los callbacks, las Promises y async/await.

async function obtenerDatos() {
  const datos = await consulta();
  return datos;
}

La asincronía es especialmente relevante cuando un programa realiza operaciones de entrada y salida.

4. Non-blocking I/O

Las operaciones de entrada y salida pueden realizarse sin mantener bloqueado el flujo principal de JavaScript mientras esperan resultados.

Por ejemplo, una aplicación puede solicitar la lectura de un archivo y continuar con otras tareas mientras el sistema procesa esa operación.

La idea general es:

JavaScript
   ->
Solicitud de I/O
   ->
Continúa ejecución
   ->
Resultado disponible

5. Módulos

Node.js permite dividir una aplicación en módulos para organizar código y controlar qué partes pueden ser utilizadas desde otros archivos.

El ecosistema de Node.js incluye módulos integrados y también permite instalar paquetes externos.

Con CommonJS pueden encontrarse estructuras como:

const fs = require('fs');

También existe el sistema de módulos ECMAScript, que utiliza import y export.

6. npm y paquetes

npm es una herramienta utilizada para administrar paquetes y dependencias en proyectos de Node.js.

Un proyecto puede declarar sus dependencias en package.json y utilizar comandos de npm para instalarlas y administrarlas.

package.json
   ->
dependencias
   ->
npm install
   ->
node_modules

Esto permite incorporar bibliotecas externas sin tener que implementar desde cero toda su funcionalidad.

7. Sistema de archivos

Node.js proporciona el módulo fs para trabajar con archivos y directorios.

Por ejemplo, una aplicación puede leer el contenido de un archivo mediante operaciones síncronas o asíncronas.

const fs = require('fs');

fs.readFile('archivo.txt', 'utf8', (err, data) => {
  if (err) throw err;
  console.log(data);
});

El acceso al sistema de archivos es una de las operaciones de entrada y salida habituales en aplicaciones de Node.js.

8. HTTP y servidores

Node.js incluye herramientas para crear servidores HTTP sin depender necesariamente de un framework externo.

Un servidor básico puede crearse mediante el módulo http:

const http = require('http');

const server = http.createServer((req, res) => {
  res.end('Hola');
});

server.listen(3000);

Esto proporciona una base para construir servidores y APIs.

9. Eventos y EventEmitter

El sistema de eventos es otra parte importante de Node.js. La clase EventEmitter permite registrar funciones que se ejecutan cuando ocurre un evento.

Por ejemplo:

const EventEmitter = require('events');

const eventos = new EventEmitter();

eventos.on('mensaje', () => {
  console.log('Evento recibido');
});

eventos.emit('mensaje');

Este mecanismo permite que distintas partes de un programa reaccionen ante eventos sin tener que invocarse directamente en todos los casos.

10. Streams

Los Streams permiten procesar datos de forma progresiva en lugar de requerir que todo el contenido esté disponible al mismo tiempo.

Son especialmente útiles para trabajar con datos que pueden procesarse por partes, como archivos o flujos de red.

La idea puede representarse así:

Fuente de datos
   ->
Stream
   ->
Procesamiento
   ->
Destino

11. Buffers

Los Buffers proporcionan una forma de trabajar con datos binarios directamente en Node.js.

Son necesarios en situaciones donde los datos no están representados únicamente como texto, por ejemplo al trabajar con archivos, conexiones de red u otros datos binarios.

Un Buffer puede crearse así:

const buffer = Buffer.from('Hola');

Su función es distinta de la de una cadena de texto, aunque puede utilizarse para convertir información entre diferentes representaciones.

12. Procesos y variables de entorno

Node.js proporciona acceso al proceso que está ejecutando la aplicación mediante process.

Por ejemplo, las variables de entorno pueden consultarse mediante process.env:

const puerto = process.env.PORT;

También pueden obtenerse argumentos de la línea de comandos mediante process.argv.

Esto permite adaptar el comportamiento del programa según el entorno donde se ejecuta.

13. Manejo de errores

Las aplicaciones de Node.js deben manejar los errores generados durante operaciones síncronas y asíncronas.

En código basado en Promises puede utilizarse try/catch junto con async/await:

async function ejecutar() {
  try {
    const resultado = await operacion();
    return resultado;
  } catch (error) {
    console.error(error);
  }
}

El manejo de errores evita que los fallos queden sin tratar y permite definir cómo debe reaccionar la aplicación cuando una operación no puede completarse.

Consideraciones

Los pilares de Node.js no deben entenderse como características aisladas. El modelo de ejecución, el Event Loop, la asincronía y las operaciones de entrada y salida están relacionados con la forma en que Node.js procesa trabajo.

Sobre esa base se construyen otras piezas, como módulos, paquetes, servidores HTTP, eventos, streams, buffers y procesos.

Entender estos conceptos permite pasar de utilizar Node.js como una herramienta a comprender cómo se estructura y ejecuta una aplicación basada en este entorno.

© Arturo Juárez Monroy