Con el entorno instalado y la carpeta escena-viva/ creada, es el momento de escribir código. En esta lección construiremos el primer programa real del proyecto: src/catalogo.js, un script que define el catálogo de eventos de Escena Viva y lo muestra por consola, con la posibilidad de filtrarlo por sala desde la línea de comandos.
Por el camino descubrirás las diferencias prácticas entre ejecutar JavaScript en el navegador y en Node.js, conocerás el objeto process, aprenderás a distinguir la salida estándar de la salida de error y sabrás qué significa el código de salida de un programa. Son conceptos que parecen menores y que resultan fundamentales en cuanto tu código deja de ser un ejercicio y pasa a integrarse en un servidor o en una tubería de despliegue.
Contenido
- Escribir y ejecutar el primer script
- El navegador y Node.js: lo que hay y lo que no
- El objeto
process: la ventana al sistema - El catálogo de Escena Viva:
src/catalogo.js - Mostrar datos:
console.log,console.tabley plantillas de cadena - Leer argumentos con
process.argv console.error, stdout y stderr- Códigos de salida y
process.exit - Depurar el típico error de sintaxis
- Qué no hace todavía este programa
- Escribir y ejecutar el primer script
Sitúate en la carpeta del proyecto y crea un fichero de prueba dentro de src/:
Crea src/hola.js con este contenido:
// src/hola.js
// El primer programa del curso: comprobar que Node ejecuta nuestro código.
console.log('Escena Viva: entorno operativo');
console.log('Version de Node:', process.version);
console.log('Directorio de trabajo:', process.cwd());Ejecútalo:
Escena Viva: entorno operativo Version de Node: v24.5.0 Directorio de trabajo: /home/usuario/proyectos/escena-viva
Tres detalles importantes de esta primera ejecución:
- La ruta es relativa al directorio desde el que ejecutas
node, no al fichero. Si estuvieras dentro desrc/, el comando seríanode hola.js. - La extensión
.jses opcional:node src/holatambién funciona. Escríbela siempre de todas formas; es más claro. - No hay compilación ni configuración previa. No hace falta
package.json, ni instalar nada, ni declarar unmain. Node lee el fichero y lo ejecuta.
- El navegador y Node.js: lo que hay y lo que no
Si vienes del desarrollo front-end, tu instinto será usar cosas que aquí no existen. Comprobémoslo:
// src/diferencias.js
// Qué objetos globales existen en Node y cuáles no.
console.log('typeof window :', typeof window); // undefined
console.log('typeof document :', typeof document); // undefined
console.log('typeof alert :', typeof alert); // undefined
console.log('typeof global :', typeof global); // object
console.log('typeof process :', typeof process); // object
console.log('typeof console :', typeof console); // object
console.log('typeof fetch :', typeof fetch); // functiontypeof window : undefined typeof document : undefined typeof alert : undefined typeof global : object typeof process : object typeof console : object typeof fetch : function
Resumen de equivalencias:
| Tarea | Navegador | Node.js |
|---|---|---|
| Objeto global | window |
global |
| Objeto global (estándar en ambos) | globalThis |
globalThis |
| Mostrar información | console.log, alert |
console.log (no hay alert) |
| Manipular la interfaz | document.querySelector(...) |
No existe: no hay interfaz |
| Petición HTTP | fetch (con restricciones CORS) |
fetch (sin CORS) o módulos http/https |
| Guardar datos localmente | localStorage |
Ficheros (fs) o base de datos |
| Leer parámetros de entrada | location.search |
process.argv |
| Variables de configuración | Incrustadas en el bundle | process.env |
| Terminar la ejecución | Cerrar la pestaña | process.exit() |
| Temporizadores | setTimeout, setInterval |
Los mismos, más setImmediate |
console.log funciona en ambos entornos, pero no hace lo mismo: en el navegador escribe en la consola de las herramientas de desarrollo; en Node escribe en la salida estándar del proceso, que es lo que ves en la terminal y lo que puede redirigirse a un fichero o a otro programa. Volveremos a ello en el apartado 7.
- El objeto
process: la ventana al sistema
process: la ventana al sistemaprocess es un objeto global que representa el proceso del sistema operativo en el que corre tu programa. Es la puerta de entrada a todo lo que rodea a tu código.
| Propiedad o método | Qué ofrece |
|---|---|
process.argv |
Array con los argumentos de la línea de comandos |
process.env |
Objeto con las variables de entorno |
process.version |
Versión de Node (v24.5.0) |
process.platform |
'linux', 'darwin', 'win32' |
process.cwd() |
Directorio de trabajo actual |
process.uptime() |
Segundos que lleva vivo el proceso |
process.memoryUsage() |
Uso de memoria en bytes |
process.exit(codigo) |
Termina el proceso con un código de salida |
process.exitCode |
Fija el código de salida sin cortar la ejecución |
process.stdout / process.stderr |
Flujos de salida estándar y de error |
Un ejemplo útil para diagnosticar entornos:
// src/entorno.js
// Diagnóstico rápido del entorno de ejecución de Escena Viva.
const memoria = process.memoryUsage();
console.log(`Node : ${process.version}`);
console.log(`Plataforma : ${process.platform}`);
console.log(`Directorio : ${process.cwd()}`);
console.log(`Memoria heap: ${Math.round(memoria.heapUsed / 1024 / 1024)} MB`);Node : v24.5.0 Plataforma : linux Directorio : /home/usuario/proyectos/escena-viva Memoria heap: 5 MB
- El catálogo de Escena Viva:
src/catalogo.js
src/catalogo.jsAhora el programa de verdad. Escena Viva gestiona eventos en tres salas: Teatro Almendra, Sala Bóveda y Auditorio Ribera. Cada evento tiene una o varias sesiones, y cada sesión tiene fecha, aforo, entradas vendidas y precio.
Una decisión de diseño que adoptamos desde el primer minuto: los precios se guardan en céntimos, como número entero. Nunca 25.50, siempre 2550. La razón es que el tipo number de JavaScript es de coma flotante y produce sorpresas como 0.1 + 0.2 === 0.30000000000000004. Con dinero eso es inaceptable. Formalizaremos esta y otras convenciones en El Proyecto del Curso.
Crea src/catalogo.js:
// src/catalogo.js
// Catalogo de eventos de Escena Viva.
// Por ahora los datos estan escritos en el propio fichero; en el modulo 3
// los leeremos desde datos/eventos.json.
const catalogo = [
{
id: 'evt-001',
titulo: 'Concierto de Otono',
sala: 'Teatro Almendra',
categoria: 'concierto',
duracionMinutos: 95,
sesiones: [
{ id: 'ses-001-1', fechaHora: '2026-10-03T20:00:00', aforo: 420, vendidas: 180, precioCentimos: 2500 },
{ id: 'ses-001-2', fechaHora: '2026-10-04T19:00:00', aforo: 420, vendidas: 96, precioCentimos: 2200 }
]
},
{
id: 'evt-002',
titulo: 'Noche de Monologos',
sala: 'Sala Boveda',
categoria: 'humor',
duracionMinutos: 80,
sesiones: [
{ id: 'ses-002-1', fechaHora: '2026-10-10T21:30:00', aforo: 120, vendidas: 118, precioCentimos: 1800 },
{ id: 'ses-002-2', fechaHora: '2026-10-11T21:30:00', aforo: 120, vendidas: 45, precioCentimos: 1800 },
{ id: 'ses-002-3', fechaHora: '2026-10-17T21:30:00', aforo: 120, vendidas: 12, precioCentimos: 1500 }
]
},
{
id: 'evt-003',
titulo: 'Festival de Jazz de Primavera',
sala: 'Auditorio Ribera',
categoria: 'festival',
duracionMinutos: 240,
sesiones: [
{ id: 'ses-003-1', fechaHora: '2027-04-17T19:00:00', aforo: 900, vendidas: 640, precioCentimos: 3800 },
{ id: 'ses-003-2', fechaHora: '2027-04-18T19:00:00', aforo: 900, vendidas: 720, precioCentimos: 4200 }
]
}
];Fíjate en un detalle deliberado: los valores de texto que van a formar parte de identificadores o de nombres de fichero evitan tildes y ñ (Concierto de Otono, Sala Boveda). En los datos que se muestran al usuario final acabaremos usando la ortografía correcta, pero mientras trabajamos por consola y con nombres técnicos, mantenerlo simple ahorra problemas de codificación. Es una convención del proyecto, no una limitación de Node.
- Mostrar datos:
console.log, console.table y plantillas de cadena
console.log, console.table y plantillas de cadenaAñade a continuación, en el mismo fichero, una función que formatee el precio y otra que imprima el catálogo.
// --- Utilidades de presentacion ---
// Convierte 2500 (centimos) en la cadena "25,00 EUR".
function formatearPrecio(centimos) {
const euros = Math.floor(centimos / 100);
const resto = String(centimos % 100).padStart(2, '0');
return `${euros},${resto} EUR`;
}
// Convierte "2026-10-03T20:00:00" en "03/10/2026 20:00".
function formatearFecha(fechaISO) {
const fecha = new Date(fechaISO);
const dia = String(fecha.getDate()).padStart(2, '0');
const mes = String(fecha.getMonth() + 1).padStart(2, '0');
const anio = fecha.getFullYear();
const hora = String(fecha.getHours()).padStart(2, '0');
const minuto = String(fecha.getMinutes()).padStart(2, '0');
return `${dia}/${mes}/${anio} ${hora}:${minuto}`;
}Explicación de las piezas nuevas para quien venga con JavaScript básico:
- Plantillas de cadena (backticks):
`${euros},${resto} EUR`permite incrustar expresiones dentro de una cadena sin concatenar con+. Es más legible y admite saltos de línea reales. padStart(2, '0'): rellena por la izquierda hasta alcanzar 2 caracteres. Convierte5en"05", que es lo que queremos en fechas y céntimos.Math.floor(2500 / 100)da los euros enteros;2500 % 100da los céntimos sobrantes. Trabajando siempre con enteros no hay errores de redondeo.
Ahora la impresión del listado:
// --- Presentacion del catalogo ---
function mostrarCatalogo(eventos) {
console.log('');
console.log('==========================================');
console.log(' ESCENA VIVA - CATALOGO DE EVENTOS');
console.log('==========================================');
for (const evento of eventos) {
// Total de entradas disponibles sumando todas las sesiones.
let disponiblesTotales = 0;
for (const sesion of evento.sesiones) {
disponiblesTotales += sesion.aforo - sesion.vendidas;
}
console.log('');
console.log(`${evento.titulo} [${evento.id}]`);
console.log(` Sala : ${evento.sala}`);
console.log(` Categoria : ${evento.categoria}`);
console.log(` Duracion : ${evento.duracionMinutos} min`);
console.log(` Sesiones : ${evento.sesiones.length}`);
console.log(` Libres : ${disponiblesTotales} entradas`);
for (const sesion of evento.sesiones) {
const libres = sesion.aforo - sesion.vendidas;
const ocupacion = Math.round((sesion.vendidas / sesion.aforo) * 100);
console.log(
` - ${formatearFecha(sesion.fechaHora)} ` +
`${formatearPrecio(sesion.precioCentimos)} ` +
`${libres}/${sesion.aforo} libres (${ocupacion}% ocupado)`
);
}
}
console.log('');
}console.table: una tabla sin esfuerzo
Node incluye console.table, que dibuja un array de objetos como tabla ASCII. Es ideal para inspeccionar datos rápidamente.
// Vista compacta en forma de tabla.
function mostrarTablaResumen(eventos) {
// Construimos un array "plano": console.table espera objetos simples.
const filas = eventos.map((evento) => {
let aforoTotal = 0;
let vendidasTotales = 0;
for (const sesion of evento.sesiones) {
aforoTotal += sesion.aforo;
vendidasTotales += sesion.vendidas;
}
return {
Evento: evento.titulo,
Sala: evento.sala,
Sesiones: evento.sesiones.length,
Aforo: aforoTotal,
Vendidas: vendidasTotales,
Ocupacion: `${Math.round((vendidasTotales / aforoTotal) * 100)}%`
};
});
console.table(filas);
}Salida:
┌─────────┬────────────────────────────────┬────────────────────┬──────────┬───────┬──────────┬───────────┐ │ (index) │ Evento │ Sala │ Sesiones │ Aforo │ Vendidas │ Ocupacion │ ├─────────┼────────────────────────────────┼────────────────────┼──────────┼───────┼──────────┼───────────┤ │ 0 │ 'Concierto de Otono' │ 'Teatro Almendra' │ 2 │ 840 │ 276 │ '33%' │ │ 1 │ 'Noche de Monologos' │ 'Sala Boveda' │ 3 │ 360 │ 175 │ '49%' │ │ 2 │ 'Festival de Jazz de Primavera'│ 'Auditorio Ribera' │ 2 │ 1800 │ 1360 │ '76%' │ └─────────┴────────────────────────────────┴────────────────────┴──────────┴───────┴──────────┴───────────┘
Otros métodos de console que conviene conocer:
| Método | Uso |
|---|---|
console.log(...) |
Salida normal (stdout) |
console.error(...) |
Salida de error (stderr) |
console.warn(...) |
Igual que error: va a stderr |
console.table(array) |
Tabla ASCII |
console.dir(obj, { depth: null }) |
Inspecciona un objeto anidado sin recortarlo |
console.time('t') / console.timeEnd('t') |
Mide cuánto tarda un bloque |
console.count('x') |
Cuenta cuántas veces se pasa por un punto |
- Leer argumentos con
process.argv
process.argvQueremos poder ejecutar:
y ver solo los eventos de esa sala. Los argumentos llegan en process.argv, un array de cadenas.
[ '/home/usuario/.nvm/versions/node/v24.5.0/bin/node', '/home/usuario/proyectos/escena-viva/src/catalogo.js', 'Sala Boveda', '--tabla' ]
La estructura es siempre la misma:
| Índice | Contenido |
|---|---|
0 |
Ruta absoluta del ejecutable de Node |
1 |
Ruta absoluta del script ejecutado |
2 en adelante |
Los argumentos que ha escrito el usuario |
De ahí el idioma habitual: process.argv.slice(2).
// --- Lectura de argumentos ---
const argumentos = process.argv.slice(2);
// El primer argumento que no empiece por "--" se interpreta como sala.
const salaFiltro = argumentos.find((arg) => !arg.startsWith('--'));
const usarTabla = argumentos.includes('--tabla');
// Filtramos el catálogo si se ha indicado una sala.
let eventosMostrados = catalogo;
if (salaFiltro) {
eventosMostrados = catalogo.filter(
(evento) => evento.sala.toLowerCase() === salaFiltro.toLowerCase()
);
}Comparar en minúsculas con toLowerCase() hace el filtro tolerante: "sala boveda" y "Sala Boveda" funcionan igual. Es un detalle pequeño con un gran efecto en la usabilidad de una herramienta de línea de comandos.
Para argumentos más complejos (opciones con valor, banderas combinadas), Node incluye
util.parseArgs, y el ecosistema ofrece paquetes comocommanderoyargs. Los veremos cuando lleguemos a npm en el Módulo 5.
console.error, stdout y stderr
console.error, stdout y stderrTodo proceso del sistema operativo dispone de dos canales de salida separados:
- stdout (salida estándar): el resultado útil del programa.
- stderr (salida de error): mensajes de error, avisos y diagnósticos.
Están separados por una razón práctica: permite redirigir el resultado a un fichero sin mezclarlo con los errores.
# Solo el catálogo va al fichero; los errores siguen apareciendo en pantalla
node src/catalogo.js > informes/catalogo.txt
# Redirigir también los errores a otro fichero
node src/catalogo.js > informes/catalogo.txt 2> informes/errores.txtflowchart LR
P["Proceso Node<br/>src/catalogo.js"] -->|"stdout (1)<br/>console.log"| A["Terminal o<br/>informes/catalogo.txt"]
P -->|"stderr (2)<br/>console.error"| B["Terminal o<br/>informes/errores.txt"]
Si mezclas errores en console.log, quien redirija tu salida a un fichero se encontrará mensajes de error incrustados entre los datos. Regla: los datos por console.log, todo lo demás por console.error.
Apliquémoslo al filtro por sala:
// --- Validacion del filtro ---
if (salaFiltro && eventosMostrados.length === 0) {
// Esto es un diagnostico, no un dato: va a stderr.
console.error(`Error: no hay eventos en la sala "${salaFiltro}".`);
console.error('Salas disponibles:');
for (const sala of new Set(catalogo.map((evento) => evento.sala))) {
console.error(` - ${sala}`);
}
process.exit(1);
}new Set(...) elimina duplicados: si dos eventos comparten sala, solo aparece una vez. Lo veremos con más calma en JavaScript Moderno para Node.js.
- Códigos de salida y
process.exit
process.exitCuando un programa termina, devuelve al sistema operativo un número entero: el código de salida.
| Código | Significado convencional |
|---|---|
0 |
Éxito |
1 |
Error genérico |
2 |
Uso incorrecto (argumentos mal escritos) |
> 2 |
Códigos específicos que define tu aplicación |
Puedes consultarlo tras ejecutar un comando:
Esto es lo que permite encadenar comandos con seguridad en un despliegue:
# El informe solo se genera si el catálogo se validó correctamente
node src/catalogo.js --validar && node src/informe.jsprocess.exit() con responsabilidad
process.exit(1) corta el proceso de inmediato. Es un instrumento contundente: si hay escrituras de fichero o respuestas de red pendientes, pueden quedarse a medias.
La alternativa recomendada en la mayoría de casos es asignar process.exitCode y dejar que el programa termine de forma natural:
// Preferible: marca el código de salida pero deja terminar limpiamente
if (salaFiltro && eventosMostrados.length === 0) {
console.error(`Error: no hay eventos en la sala "${salaFiltro}".`);
process.exitCode = 1;
return; // Si estamos dentro de una función
}| Forma | Cuándo usarla |
|---|---|
process.exitCode = 1 |
Casi siempre: seguro, deja que se completen las tareas pendientes |
process.exit(1) |
Errores fatales en scripts sencillos, o cuando debes cortar sin remedio |
Cerramos el fichero con la ejecución:
// --- Ejecucion ---
if (usarTabla) {
mostrarTablaResumen(eventosMostrados);
} else {
mostrarCatalogo(eventosMostrados);
}
console.log(`Total: ${eventosMostrados.length} evento(s) mostrado(s).`);Pruébalo:
node src/catalogo.js # Todo el catálogo, formato detallado
node src/catalogo.js --tabla # Todo el catálogo, formato tabla
node src/catalogo.js "Teatro Almendra" # Solo una sala
node src/catalogo.js "Sala Inexistente" # Error controlado, código de salida 1
- Depurar el típico error de sintaxis
Introduce deliberadamente un fallo: borra una llave de cierre en el array catalogo y ejecuta el script.
/home/usuario/proyectos/escena-viva/src/catalogo.js:34
];
^
SyntaxError: Unexpected token ']'
at wrapSafe (node:internal/modules/cjs/loader:1281:20)
at Module._compile (node:internal/modules/cjs/loader:1321:27)
...
Node.js v24.5.0Cómo leer este mensaje, de arriba abajo:
.../src/catalogo.js:34: fichero y línea donde Node se dio cuenta del problema.- El fragmento de código y el
^: el token exacto que no encajaba. SyntaxError: Unexpected token ']': el tipo de error.- La pila de llamadas (
at wrapSafe...): en errores de sintaxis son funciones internas de Node; ignórala, no aporta nada.
Punto clave que confunde a mucha gente: la línea que indica Node es donde el analizador se atragantó, no necesariamente donde está el fallo. Si olvidas una llave en la línea 20, el error puede señalar la 34. Busca hacia arriba desde la línea indicada.
Errores frecuentes y su mensaje:
| Mensaje | Causa habitual |
|---|---|
SyntaxError: Unexpected token '}' |
Llave, paréntesis o corchete de más o mal cerrado |
SyntaxError: Unexpected end of input |
Falta un cierre al final del fichero |
ReferenceError: catalogo is not defined |
Nombre mal escrito o variable usada antes de declararla |
TypeError: Cannot read properties of undefined (reading 'sesiones') |
Accediste a una propiedad de algo que vale undefined |
Error: Cannot find module '/ruta/src/catalog.js' |
Nombre de fichero o ruta equivocados |
Ese último es muy típico al principio: Cannot find module casi siempre significa que ejecutaste node catalogo.js desde la raíz en lugar de node src/catalogo.js.
Un editor con ESLint te habría marcado el error antes de guardar. Por eso la lección anterior insistía en configurarlo.
- Qué no hace todavía este programa
Es tan importante saber qué has construido como qué te falta:
| Limitación actual | Dónde se resuelve |
|---|---|
Los datos están escritos dentro del .js; cambiar el catálogo obliga a tocar código |
Módulo 3: leeremos datos/eventos.json con fs |
| Solo se ve por terminal; no hay forma de consultarlo desde un navegador | Módulo 4: serviremos el catálogo por HTTP |
| Todo el código vive en un único fichero | Módulo 2: separaremos en módulos con require/module.exports |
| No hay persistencia de pedidos ni usuarios | Módulo 7: base de datos escena_viva |
| El parseo de argumentos es artesanal | Módulo 5: paquetes especializados |
Ese es exactamente el camino del curso: el mismo src/catalogo.js irá creciendo y transformándose módulo a módulo hasta ser una API real.
Errores Comunes y Consejos
Error 1: usar window, document o alert.
No existen en Node. Si un tutorial los usa, está hablando del navegador.
Error 2: creer que process.argv[0] es el primer argumento del usuario.
Es la ruta del ejecutable de Node. Los argumentos del usuario empiezan en el índice 2; usa siempre process.argv.slice(2).
Error 3: mandar los errores por console.log.
Contamina la salida de datos. Los errores y avisos van por console.error.
Error 4: llamar a process.exit() a mitad de una operación.
Corta el proceso sin esperar a que terminen escrituras pendientes. Prefiere process.exitCode.
Error 5: ejecutar el script desde el directorio equivocado.
Cannot find module suele significar eso. Comprueba process.cwd().
Error 6: buscar el error de sintaxis exactamente en la línea que indica Node. El analizador señala dónde falló, no dónde está el descuido. Mira las líneas anteriores.
Consejo 1: usa console.table para inspeccionar datos. Es mucho más legible que un console.log de un array de objetos.
Consejo 2: mide con console.time. Envolver un bloque entre console.time('carga') y console.timeEnd('carga') es la forma más barata de saber qué tarda.
Consejo 3: piensa tus scripts como comandos. Argumentos claros, datos por stdout, errores por stderr y código de salida correcto. Así podrás encadenarlos con otras herramientas.
Ejercicios
Ejercicio 1: información del entorno
Crea src/entorno.js que imprima una tabla (con console.table) con estas filas: versión de Node, plataforma, arquitectura (process.arch), directorio de trabajo, número de argumentos recibidos y memoria heap usada en MB. Ejecútalo con y sin argumentos extra y comprueba que el recuento cambia.
Ejercicio 2: filtro por precio máximo
Amplía src/catalogo.js para aceptar un segundo filtro: --max=2000 debe mostrar solo los eventos que tengan al menos una sesión cuyo precioCentimos sea menor o igual a ese valor. Requisitos:
- Debe combinarse con el filtro de sala:
node src/catalogo.js "Sala Boveda" --max=1600. - Si el valor de
--maxno es un número válido, escribe un mensaje porconsole.errory termina con código de salida2.
Ejercicio 3: informe de ocupación con código de salida
Crea src/alerta-aforo.js que recorra el catálogo y liste por console.log todas las sesiones con menos del 20% de entradas vendidas (las que hay que promocionar). Reglas:
- Formato de cada línea:
evt-002 | ses-002-3 | 17/10/2026 21:30 | 10% vendido. - Si no hay ninguna sesión en esa situación, escribe
Sin sesiones en riesgoy termina con código0. - Si hay alguna, termina con código de salida
1, para que un sistema de avisos pueda detectarlo.
Soluciones
Solución 1
// src/entorno.js
// Diagnostico del entorno de ejecucion en forma de tabla.
const memoria = process.memoryUsage();
const argumentos = process.argv.slice(2);
const datos = [
{ Dato: 'Version de Node', Valor: process.version },
{ Dato: 'Plataforma', Valor: process.platform },
{ Dato: 'Arquitectura', Valor: process.arch },
{ Dato: 'Directorio', Valor: process.cwd() },
{ Dato: 'Argumentos', Valor: argumentos.length },
{ Dato: 'Heap usado (MB)', Valor: Math.round(memoria.heapUsed / 1024 / 1024) }
];
console.table(datos);Solución 2
// --- Filtro por precio maximo ---
// Buscamos un argumento con la forma --max=NNNN
const argumentoMax = argumentos.find((arg) => arg.startsWith('--max='));
if (argumentoMax) {
// Todo lo que hay tras el signo "=" es el valor.
const valorTexto = argumentoMax.split('=')[1];
const precioMaximo = Number(valorTexto);
// Number('abc') devuelve NaN; Number('') devuelve 0, que tampoco vale aqui.
if (!Number.isInteger(precioMaximo) || precioMaximo <= 0) {
console.error(`Error: valor invalido en --max ("${valorTexto}").`);
console.error('Uso: node src/catalogo.js [sala] [--max=CENTIMOS] [--tabla]');
process.exit(2); // 2 = uso incorrecto
}
eventosMostrados = eventosMostrados.filter((evento) =>
// some() devuelve true si AL MENOS una sesion cumple la condicion.
evento.sesiones.some((sesion) => sesion.precioCentimos <= precioMaximo)
);
}Este bloque debe colocarse después del filtro de sala, para que ambos se combinen: cada filtro reduce el resultado del anterior.
node src/catalogo.js --max=2000 # Noche de Monologos (1800 y 1500)
node src/catalogo.js "Sala Boveda" --max=1600 # Solo por la sesion de 1500
node src/catalogo.js --max=abc # Error, codigo de salida 2Solución 3
// src/alerta-aforo.js
// Lista las sesiones con baja venta para lanzar acciones de promocion.
const catalogo = require('./catalogo-datos.js'); // (ver nota al final)
const UMBRAL_PORCENTAJE = 20;
const enRiesgo = [];
for (const evento of catalogo) {
for (const sesion of evento.sesiones) {
const porcentaje = Math.round((sesion.vendidas / sesion.aforo) * 100);
if (porcentaje < UMBRAL_PORCENTAJE) {
enRiesgo.push({ evento, sesion, porcentaje });
}
}
}
if (enRiesgo.length === 0) {
console.log('Sin sesiones en riesgo');
process.exitCode = 0;
} else {
for (const item of enRiesgo) {
console.log(
`${item.evento.id} | ${item.sesion.id} | ` +
`${formatearFecha(item.sesion.fechaHora)} | ${item.porcentaje}% vendido`
);
}
// Codigo distinto de 0 para que un sistema de avisos lo detecte.
process.exitCode = 1;
}Salida esperada con nuestros datos:
Nota sobre el require de la primera línea: para que este segundo script use los mismos datos habría que exportarlos desde un fichero común. Todavía no hemos visto cómo hacerlo —es el tema de Módulos CommonJS y require()—, así que de momento copia el array catalogo y la función formatearFecha dentro de src/alerta-aforo.js. Que esa duplicación te resulte incómoda es precisamente el motivo por el que existen los módulos.
Conclusión
Has escrito y ejecutado tu primer programa real en Node.js. Por el camino has visto que JavaScript en el servidor no tiene window ni document, pero sí process, el objeto que te conecta con el sistema operativo: argumentos, entorno, directorio de trabajo, memoria y código de salida.
Has construido src/catalogo.js con los tres eventos fundacionales de Escena Viva —el Concierto de Otoño en el Teatro Almendra, la Noche de Monólogos en la Sala Bóveda y el Festival de Jazz de Primavera en el Auditorio Ribera—, lo has formateado con plantillas de cadena y console.table, lo has filtrado con process.argv y has aprendido a separar los datos (stdout) de los diagnósticos (stderr), cerrando con un código de salida coherente. También sabes leer un SyntaxError sin asustarte: fichero, línea, token y a mirar hacia arriba.
Todo esto lo has hecho editando un fichero, guardándolo y volviendo a ejecutar. Existe una forma mucho más ágil de probar ideas sueltas —una expresión, una transformación del catálogo, una duda sobre cómo se comporta un método— sin ese ciclo de guardar y ejecutar. En la siguiente lección, El REPL de Node.js, aprenderás a usar el intérprete interactivo para explorar los datos de Escena Viva en vivo y probar transformaciones antes de escribirlas en el script.
Curso de Node.js: De Principiante a Avanzado
Módulo 1: Introducción a Node.js
- ¿Qué es Node.js?
- Instalación y Configuración del Entorno
- Tu Primer Programa en Node.js
- El REPL de Node.js
- JavaScript Moderno para Node.js
- El Proyecto del Curso: la Plataforma Escena Viva
Módulo 2: Conceptos Básicos
- Arquitectura de Node.js
- El Bucle de Eventos (Event Loop)
- Callbacks y Programación Asíncrona
- Promesas y async/await
- Eventos y EventEmitter
- Módulos CommonJS y require()
- Módulos ES e Interoperabilidad
Módulo 3: Sistema de Archivos y E/S
- Lectura y Escritura de Archivos
- El Módulo fs a Fondo
- Rutas Multiplataforma con el Módulo path
- Trabajando con Streams
- Streams de Transformación y pipeline
- Buffers y Datos Binarios
Módulo 4: HTTP y Servidores Web
- Creando un Servidor HTTP Simple
- Manejo de Solicitudes y Respuestas
- Enrutamiento Manual
- Sirviendo Archivos Estáticos
- Recibiendo Datos: Cuerpos de Petición y JSON
- Consumiendo APIs Externas desde Node.js
Módulo 5: NPM y Gestión de Paquetes
- Introducción a NPM y package.json
- Instalación y Uso de Paquetes
- Versionado Semántico y package-lock
- Scripts de npm y Automatización del Proyecto
- Creación y Publicación de Paquetes
- Seguridad y Mantenimiento de Dependencias
Módulo 6: Framework Express.js
- Introducción a Express.js
- Configuración de una Aplicación Express
- Enrutamiento en Express
- Middleware
- Middleware de Terceros Esenciales
- Validación de Datos de Entrada
- Manejo de Errores
Módulo 7: Bases de Datos y ORMs
- Introducción a las Bases de Datos
- Usando MongoDB con Mongoose
- Operaciones CRUD
- Relaciones, Poblado y Consultas Avanzadas
- Usando Bases de Datos SQL con Sequelize
- Migraciones, Transacciones y Datos de Prueba
Módulo 8: Autenticación y Autorización
- Introducción a la Autenticación
- Registro de Usuarios y Hash de Contraseñas
- Sesiones y Cookies con Passport.js
- Autenticación con JWT
- Control de Acceso Basado en Roles
- Buenas Prácticas de Seguridad en APIs
Módulo 9: Pruebas y Depuración
- Introducción a las Pruebas
- Pruebas Unitarias con Mocha y Chai
- Dobles de Prueba con Sinon
- Pruebas de Integración
- Cobertura y Automatización de las Pruebas
- Depuración de Aplicaciones Node.js
Módulo 10: Temas Avanzados
- El Módulo Cluster
- Hilos de Trabajo (Worker Threads)
- Caché y Colas de Trabajo con Redis
- Optimización del Rendimiento
- Construcción de APIs RESTful
- GraphQL con Node.js
Módulo 11: Despliegue y DevOps
- Configuración y Variables de Entorno
- Registro y Monitorización en Producción
- Usando PM2 para la Gestión de Procesos
- Empaquetado con Docker
- Desplegando en Heroku y Otras PaaS
- Integración y Despliegue Continuos
