Amb l'entorn instal·lat i la carpeta escena-viva/ creada, és el moment d'escriure codi. En aquesta lliçó construirem el primer programa real del projecte: src/cataleg.js, un script que defineix el catàleg d'esdeveniments d'Escena Viva i el mostra per consola, amb la possibilitat de filtrar-lo per sala des de la línia d'ordres.
Pel camí descobriràs les diferències pràctiques entre executar JavaScript al navegador i a Node.js, coneixeràs l'objecte process, aprendràs a distingir la sortida estàndard de la sortida d'error i sabràs què significa el codi de sortida d'un programa. Són conceptes que semblen menors i que resulten fonamentals tan bon punt el teu codi deixa de ser un exercici i passa a integrar-se en un servidor o en una canonada de desplegament.
Contingut
- Escriure i executar el primer script
- El navegador i Node.js: el que hi ha i el que no
- L'objecte
process: la finestra al sistema - El catàleg d'Escena Viva:
src/cataleg.js - Mostrar dades:
console.log,console.tablei plantilles de cadena - Llegir arguments amb
process.argv console.error, stdout i stderr- Codis de sortida i
process.exit - Depurar el típic error de sintaxi
- Què no fa encara aquest programa
- Escriure i executar el primer script
Situa't a la carpeta del projecte i crea un fitxer de prova dins de src/:
Crea src/hola.js amb aquest contingut:
// src/hola.js
// El primer programa del curs: comprovar que Node executa el nostre codi.
console.log('Escena Viva: entorn operatiu');
console.log('Versio de Node:', process.version);
console.log('Directori de treball:', process.cwd());Executa'l:
Escena Viva: entorn operatiu Versio de Node: v24.5.0 Directori de treball: /home/usuari/projectes/escena-viva
Tres detalls importants d'aquesta primera execució:
- La ruta és relativa al directori des del qual executes
node, no al fitxer. Si fossis dins desrc/, l'ordre serianode hola.js. - L'extensió
.jsés opcional:node src/holatambé funciona. Escriu-la sempre igualment; és més clar. - No hi ha compilació ni configuració prèvia. No cal
package.json, ni instal·lar res, ni declarar unmain. Node llegeix el fitxer i l'executa.
- El navegador i Node.js: el que hi ha i el que no
Si véns del desenvolupament front-end, el teu instint serà fer servir coses que aquí no existeixen. Comprovem-ho:
// src/diferencies.js
// Quins objectes globals existeixen a Node i quins 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
Resum d'equivalències:
| Tasca | Navegador | Node.js |
|---|---|---|
| Objecte global | window |
global |
| Objecte global (estàndard en tots dos) | globalThis |
globalThis |
| Mostrar informació | console.log, alert |
console.log (no hi ha alert) |
| Manipular la interfície | document.querySelector(...) |
No existeix: no hi ha interfície |
| Petició HTTP | fetch (amb restriccions CORS) |
fetch (sense CORS) o mòduls http/https |
| Desar dades localment | localStorage |
Fitxers (fs) o base de dades |
| Llegir paràmetres d'entrada | location.search |
process.argv |
| Variables de configuració | Incrustades al bundle | process.env |
| Acabar l'execució | Tancar la pestanya | process.exit() |
| Temporitzadors | setTimeout, setInterval |
Els mateixos, més setImmediate |
console.log funciona en tots dos entorns, però no fa el mateix: al navegador escriu a la consola de les eines de desenvolupament; a Node escriu a la sortida estàndard del procés, que és el que veus al terminal i el que es pot redirigir a un fitxer o a un altre programa. Hi tornarem a l'apartat 7.
- L'objecte
process: la finestra al sistema
process: la finestra al sistemaprocess és un objecte global que representa el procés del sistema operatiu en què corre el teu programa. És la porta d'entrada a tot el que envolta el teu codi.
| Propietat o mètode | Què ofereix |
|---|---|
process.argv |
Array amb els arguments de la línia d'ordres |
process.env |
Objecte amb les variables d'entorn |
process.version |
Versió de Node (v24.5.0) |
process.platform |
'linux', 'darwin', 'win32' |
process.cwd() |
Directori de treball actual |
process.uptime() |
Segons que fa que el procés és viu |
process.memoryUsage() |
Ús de memòria en bytes |
process.exit(codi) |
Acaba el procés amb un codi de sortida |
process.exitCode |
Fixa el codi de sortida sense tallar l'execució |
process.stdout / process.stderr |
Fluxos de sortida estàndard i d'error |
Un exemple útil per diagnosticar entorns:
// src/entorn.js
// Diagnostic rapid de l'entorn d'execucio d'Escena Viva.
const memoria = process.memoryUsage();
console.log(`Node : ${process.version}`);
console.log(`Plataforma : ${process.platform}`);
console.log(`Directori : ${process.cwd()}`);
console.log(`Memoria heap: ${Math.round(memoria.heapUsed / 1024 / 1024)} MB`);
- El catàleg d'Escena Viva:
src/cataleg.js
src/cataleg.jsAra el programa de debò. Escena Viva gestiona esdeveniments en tres sales: Teatro Almendra, Sala Bóveda i Auditorio Ribera. Cada esdeveniment té una o diverses sessions, i cada sessió té data, aforament, entrades venudes i preu.
Una decisió de disseny que adoptem des del primer minut: els preus es desen en cèntims, com a nombre enter. Mai 25.50, sempre 2550. La raó és que el tipus number de JavaScript és de coma flotant i produeix sorpreses com 0.1 + 0.2 === 0.30000000000000004. Amb diners això és inacceptable. Formalitzarem aquesta i altres convencions a El Projecte del Curs.
Crea src/cataleg.js:
// src/cataleg.js
// Cataleg d'esdeveniments d'Escena Viva.
// De moment les dades estan escrites al propi fitxer; al modul 3
// les llegirem des de dades/esdeveniments.json.
const cataleg = [
{
id: 'evt-001',
titol: 'Concierto de Otono',
sala: 'Teatro Almendra',
categoria: 'concert',
duracioMinuts: 95,
sessions: [
{ id: 'ses-001-1', dataHora: '2026-10-03T20:00:00', aforament: 420, venudes: 180, preuCentims: 2500 },
{ id: 'ses-001-2', dataHora: '2026-10-04T19:00:00', aforament: 420, venudes: 96, preuCentims: 2200 }
]
},
{
id: 'evt-002',
titol: 'Noche de Monologos',
sala: 'Sala Boveda',
categoria: 'humor',
duracioMinuts: 80,
sessions: [
{ id: 'ses-002-1', dataHora: '2026-10-10T21:30:00', aforament: 120, venudes: 118, preuCentims: 1800 },
{ id: 'ses-002-2', dataHora: '2026-10-11T21:30:00', aforament: 120, venudes: 45, preuCentims: 1800 },
{ id: 'ses-002-3', dataHora: '2026-10-17T21:30:00', aforament: 120, venudes: 12, preuCentims: 1500 }
]
},
{
id: 'evt-003',
titol: 'Festival de Jazz de Primavera',
sala: 'Auditorio Ribera',
categoria: 'festival',
duracioMinuts: 240,
sessions: [
{ id: 'ses-003-1', dataHora: '2027-04-17T19:00:00', aforament: 900, venudes: 640, preuCentims: 3800 },
{ id: 'ses-003-2', dataHora: '2027-04-18T19:00:00', aforament: 900, venudes: 720, preuCentims: 4200 }
]
}
];Fixa't en un detall deliberat: els valors de text que formaran part d'identificadors o de noms de fitxer eviten accents i ñ (Concierto de Otono, Sala Boveda). A les dades que es mostren a l'usuari final acabarem fent servir l'ortografia correcta, però mentre treballem per consola i amb noms tècnics, mantenir-ho simple estalvia problemes de codificació. És una convenció del projecte, no una limitació de Node.
- Mostrar dades:
console.log, console.table i plantilles de cadena
console.log, console.table i plantilles de cadenaAfegeix a continuació, al mateix fitxer, una funció que formati el preu i una altra que imprimeixi el catàleg.
// --- Utilitats de presentacio ---
// Converteix 2500 (centims) en la cadena "25,00 EUR".
function formatarPreu(centims) {
const euros = Math.floor(centims / 100);
const resta = String(centims % 100).padStart(2, '0');
return `${euros},${resta} EUR`;
}
// Converteix "2026-10-03T20:00:00" en "03/10/2026 20:00".
function formatarData(dataISO) {
const data = new Date(dataISO);
const dia = String(data.getDate()).padStart(2, '0');
const mes = String(data.getMonth() + 1).padStart(2, '0');
const any = data.getFullYear();
const hora = String(data.getHours()).padStart(2, '0');
const minut = String(data.getMinutes()).padStart(2, '0');
return `${dia}/${mes}/${any} ${hora}:${minut}`;
}Explicació de les peces noves per a qui vingui amb JavaScript bàsic:
- Plantilles de cadena (cometes invertides):
`${euros},${resta} EUR`permet incrustar expressions dins d'una cadena sense concatenar amb+. És més llegible i admet salts de línia reals. padStart(2, '0'): omple per l'esquerra fins a arribar a 2 caràcters. Converteix5en"05", que és el que volem en dates i cèntims.Math.floor(2500 / 100)dona els euros sencers;2500 % 100dona els cèntims sobrants. Treballant sempre amb enters no hi ha errors d'arrodoniment.
Ara la impressió del llistat:
// --- Presentacio del cataleg ---
function mostrarCataleg(esdeveniments) {
console.log('');
console.log('==========================================');
console.log(" ESCENA VIVA - CATALEG D'ESDEVENIMENTS");
console.log('==========================================');
for (const esdeveniment of esdeveniments) {
// Total d'entrades disponibles sumant totes les sessions.
let disponiblesTotals = 0;
for (const sessio of esdeveniment.sessions) {
disponiblesTotals += sessio.aforament - sessio.venudes;
}
console.log('');
console.log(`${esdeveniment.titol} [${esdeveniment.id}]`);
console.log(` Sala : ${esdeveniment.sala}`);
console.log(` Categoria : ${esdeveniment.categoria}`);
console.log(` Durada : ${esdeveniment.duracioMinuts} min`);
console.log(` Sessions : ${esdeveniment.sessions.length}`);
console.log(` Lliures : ${disponiblesTotals} entrades`);
for (const sessio of esdeveniment.sessions) {
const lliures = sessio.aforament - sessio.venudes;
const ocupacio = Math.round((sessio.venudes / sessio.aforament) * 100);
console.log(
` - ${formatarData(sessio.dataHora)} ` +
`${formatarPreu(sessio.preuCentims)} ` +
`${lliures}/${sessio.aforament} lliures (${ocupacio}% ocupat)`
);
}
}
console.log('');
}console.table: una taula sense esforç
Node inclou console.table, que dibuixa un array d'objectes com a taula ASCII. És ideal per inspeccionar dades ràpidament.
// Vista compacta en forma de taula.
function mostrarTaulaResum(esdeveniments) {
// Construim un array "pla": console.table espera objectes simples.
const files = esdeveniments.map((esdeveniment) => {
let aforamentTotal = 0;
let venudesTotals = 0;
for (const sessio of esdeveniment.sessions) {
aforamentTotal += sessio.aforament;
venudesTotals += sessio.venudes;
}
return {
Esdeveniment: esdeveniment.titol,
Sala: esdeveniment.sala,
Sessions: esdeveniment.sessions.length,
Aforament: aforamentTotal,
Venudes: venudesTotals,
Ocupacio: `${Math.round((venudesTotals / aforamentTotal) * 100)}%`
};
});
console.table(files);
}Sortida:
┌─────────┬─────────────────────────────────┬────────────────────┬──────────┬───────────┬─────────┬──────────┐ │ (index) │ Esdeveniment │ Sala │ Sessions │ Aforament │ Venudes │ Ocupacio │ ├─────────┼─────────────────────────────────┼────────────────────┼──────────┼───────────┼─────────┼──────────┤ │ 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%' │ └─────────┴─────────────────────────────────┴────────────────────┴──────────┴───────────┴─────────┴──────────┘
Altres mètodes de console que convé conèixer:
| Mètode | Ús |
|---|---|
console.log(...) |
Sortida normal (stdout) |
console.error(...) |
Sortida d'error (stderr) |
console.warn(...) |
Igual que error: va a stderr |
console.table(array) |
Taula ASCII |
console.dir(obj, { depth: null }) |
Inspecciona un objecte imbricat sense retallar-lo |
console.time('t') / console.timeEnd('t') |
Mesura quant triga un bloc |
console.count('x') |
Compta quantes vegades es passa per un punt |
- Llegir arguments amb
process.argv
process.argvVolem poder executar:
i veure només els esdeveniments d'aquella sala. Els arguments arriben a process.argv, un array de cadenes.
[ '/home/usuari/.nvm/versions/node/v24.5.0/bin/node', '/home/usuari/projectes/escena-viva/src/cataleg.js', 'Sala Boveda', '--taula' ]
L'estructura és sempre la mateixa:
| Índex | Contingut |
|---|---|
0 |
Ruta absoluta de l'executable de Node |
1 |
Ruta absoluta de l'script executat |
2 en endavant |
Els arguments que ha escrit l'usuari |
D'aquí ve l'idioma habitual: process.argv.slice(2).
// --- Lectura d'arguments ---
const parametres = process.argv.slice(2);
// El primer parametre que no comenci per "--" s'interpreta com a sala.
const salaFiltre = parametres.find((param) => !param.startsWith('--'));
const usarTaula = parametres.includes('--taula');
// Filtrem el cataleg si s'ha indicat una sala.
let esdevenimentsMostrats = cataleg;
if (salaFiltre) {
esdevenimentsMostrats = cataleg.filter(
(esdeveniment) => esdeveniment.sala.toLowerCase() === salaFiltre.toLowerCase()
);
}Comparar en minúscules amb toLowerCase() fa el filtre tolerant: "sala boveda" i "Sala Boveda" funcionen igual. És un detall petit amb un gran efecte en la usabilitat d'una eina de línia d'ordres.
Per a arguments més complexos (opcions amb valor, indicadors combinats), Node inclou
util.parseArgs, i l'ecosistema ofereix paquets comcommanderoyargs. Els veurem quan arribem a npm al Mòdul 5.
console.error, stdout i stderr
console.error, stdout i stderrTot procés del sistema operatiu disposa de dos canals de sortida separats:
- stdout (sortida estàndard): el resultat útil del programa.
- stderr (sortida d'error): missatges d'error, avisos i diagnòstics.
Estan separats per una raó pràctica: permet redirigir el resultat a un fitxer sense barrejar-lo amb els errors.
# Nomes el cataleg va al fitxer; els errors continuen apareixent a pantalla
node src/cataleg.js > informes/cataleg.txt
# Redirigir tambe els errors a un altre fitxer
node src/cataleg.js > informes/cataleg.txt 2> informes/errors.txtflowchart LR
P["Proces Node<br/>src/cataleg.js"] -->|"stdout (1)<br/>console.log"| A["Terminal o<br/>informes/cataleg.txt"]
P -->|"stderr (2)<br/>console.error"| B["Terminal o<br/>informes/errors.txt"]
Si barreges errors dins de console.log, qui redirigeixi la teva sortida a un fitxer es trobarà missatges d'error incrustats entre les dades. Regla: les dades per console.log, tota la resta per console.error.
Apliquem-ho al filtre per sala:
// --- Validacio del filtre ---
if (salaFiltre && esdevenimentsMostrats.length === 0) {
// Aixo es un diagnostic, no una dada: va a stderr.
console.error(`Error: no hi ha esdeveniments a la sala "${salaFiltre}".`);
console.error('Sales disponibles:');
for (const sala of new Set(cataleg.map((esdeveniment) => esdeveniment.sala))) {
console.error(` - ${sala}`);
}
process.exit(1);
}new Set(...) elimina duplicats: si dos esdeveniments comparteixen sala, només apareix un cop. Ho veurem amb més calma a JavaScript Modern per a Node.js.
- Codis de sortida i
process.exit
process.exitQuan un programa acaba, retorna al sistema operatiu un nombre enter: el codi de sortida.
| Codi | Significat convencional |
|---|---|
0 |
Èxit |
1 |
Error genèric |
2 |
Ús incorrecte (arguments mal escrits) |
> 2 |
Codis específics que defineix la teva aplicació |
El pots consultar després d'executar una ordre:
Això és el que permet encadenar ordres amb seguretat en un desplegament:
# L'informe nomes es genera si el cataleg s'ha validat correctament
node src/cataleg.js --validar && node src/informe.jsprocess.exit() amb responsabilitat
process.exit(1) talla el procés immediatament. És un instrument contundent: si hi ha escriptures de fitxer o respostes de xarxa pendents, poden quedar-se a mitges.
L'alternativa recomanada en la majoria de casos és assignar process.exitCode i deixar que el programa acabi de manera natural:
// Preferible: marca el codi de sortida i deixa acabar netament
if (salaFiltre && esdevenimentsMostrats.length === 0) {
console.error(`Error: no hi ha esdeveniments a la sala "${salaFiltre}".`);
process.exitCode = 1;
return; // Si som dins d'una funcio
}| Forma | Quan fer-la servir |
|---|---|
process.exitCode = 1 |
Gairebé sempre: segur, deixa que es completin les tasques pendents |
process.exit(1) |
Errors fatals en scripts senzills, o quan has de tallar sense remei |
Tanquem el fitxer amb l'execució:
// --- Execucio ---
if (usarTaula) {
mostrarTaulaResum(esdevenimentsMostrats);
} else {
mostrarCataleg(esdevenimentsMostrats);
}
console.log(`Total: ${esdevenimentsMostrats.length} esdeveniment(s) mostrat(s).`);Prova-ho:
node src/cataleg.js # Tot el cataleg, format detallat
node src/cataleg.js --taula # Tot el cataleg, format taula
node src/cataleg.js "Teatro Almendra" # Nomes una sala
node src/cataleg.js "Sala Inexistent" # Error controlat, codi de sortida 1
- Depurar el típic error de sintaxi
Introdueix deliberadament una errada: esborra una clau de tancament de l'array cataleg i executa l'script.
/home/usuari/projectes/escena-viva/src/cataleg.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.0Com llegir aquest missatge, de dalt a baix:
.../src/cataleg.js:34: fitxer i línia on Node s'ha adonat del problema.- El fragment de codi i el
^: el token exacte que no encaixava. SyntaxError: Unexpected token ']': el tipus d'error.- La pila de crides (
at wrapSafe...): en errors de sintaxi són funcions internes de Node; ignora-la, no aporta res.
Punt clau que confon molta gent: la línia que indica Node és on l'analitzador s'ha ennuegat, no necessàriament on és l'errada. Si oblides una clau a la línia 20, l'error pot assenyalar la 34. Busca cap amunt des de la línia indicada.
Errors freqüents i el seu missatge:
| Missatge | Causa habitual |
|---|---|
SyntaxError: Unexpected token '}' |
Clau, parèntesi o claudàtor de més o mal tancat |
SyntaxError: Unexpected end of input |
Falta un tancament al final del fitxer |
ReferenceError: cataleg is not defined |
Nom mal escrit o variable feta servir abans de declarar-la |
TypeError: Cannot read properties of undefined (reading 'sessions') |
Has accedit a una propietat d'una cosa que val undefined |
Error: Cannot find module '/ruta/src/catalog.js' |
Nom de fitxer o ruta equivocats |
Aquest últim és molt típic al principi: Cannot find module gairebé sempre vol dir que has executat node cataleg.js des de l'arrel en comptes de node src/cataleg.js.
Un editor amb ESLint t'hauria marcat l'error abans de desar. Per això la lliçó anterior insistia a configurar-lo.
- Què no fa encara aquest programa
És tan important saber què has construït com què et falta:
| Limitació actual | On es resol |
|---|---|
Les dades estan escrites dins del .js; canviar el catàleg obliga a tocar codi |
Mòdul 3: llegirem dades/esdeveniments.json amb fs |
| Només es veu per terminal; no hi ha manera de consultar-ho des d'un navegador | Mòdul 4: servirem el catàleg per HTTP |
| Tot el codi viu en un únic fitxer | Mòdul 2: separarem en mòduls amb require/module.exports |
| No hi ha persistència de comandes ni usuaris | Mòdul 7: base de dades escena_viva |
| L'anàlisi d'arguments és artesanal | Mòdul 5: paquets especialitzats |
Aquest és exactament el camí del curs: el mateix src/cataleg.js anirà creixent i transformant-se mòdul a mòdul fins a ser una API real.
Errors Comuns i Consells
Error 1: fer servir window, document o alert.
No existeixen a Node. Si un tutorial els fa servir, està parlant del navegador.
Error 2: creure que process.argv[0] és el primer argument de l'usuari.
És la ruta de l'executable de Node. Els arguments de l'usuari comencen a l'índex 2; fes servir sempre process.argv.slice(2).
Error 3: enviar els errors per console.log.
Contamina la sortida de dades. Els errors i avisos van per console.error.
Error 4: cridar process.exit() a mitja operació.
Talla el procés sense esperar que acabin escriptures pendents. Prefereix process.exitCode.
Error 5: executar l'script des del directori equivocat.
Cannot find module sol voler dir això. Comprova process.cwd().
Error 6: buscar l'error de sintaxi exactament a la línia que indica Node. L'analitzador assenyala on ha fallat, no on és el descuit. Mira les línies anteriors.
Consell 1: fes servir console.table per inspeccionar dades. És molt més llegible que un console.log d'un array d'objectes.
Consell 2: mesura amb console.time. Embolcallar un bloc entre console.time('carrega') i console.timeEnd('carrega') és la manera més barata de saber què triga.
Consell 3: pensa els teus scripts com a ordres. Arguments clars, dades per stdout, errors per stderr i codi de sortida correcte. Així els podràs encadenar amb altres eines.
Exercicis
Exercici 1: informació de l'entorn
Crea src/entorn.js que imprimeixi una taula (amb console.table) amb aquestes files: versió de Node, plataforma, arquitectura (process.arch), directori de treball, nombre d'arguments rebuts i memòria heap usada en MB. Executa'l amb i sense arguments extra i comprova que el recompte canvia.
Exercici 2: filtre per preu màxim
Amplia src/cataleg.js per acceptar un segon filtre: --max=2000 ha de mostrar només els esdeveniments que tinguin almenys una sessió amb un preuCentims menor o igual a aquest valor. Requisits:
- S'ha de poder combinar amb el filtre de sala:
node src/cataleg.js "Sala Boveda" --max=1600. - Si el valor de
--maxno és un nombre vàlid, escriu un missatge perconsole.errori acaba amb codi de sortida2.
Exercici 3: informe d'ocupació amb codi de sortida
Crea src/alerta-aforament.js que recorri el catàleg i llisti per console.log totes les sessions amb menys del 20% d'entrades venudes (les que cal promocionar). Regles:
- Format de cada línia:
evt-002 | ses-002-3 | 17/10/2026 21:30 | 10% venut. - Si no hi ha cap sessió en aquesta situació, escriu
Sense sessions en risci acaba amb codi0. - Si n'hi ha alguna, acaba amb codi de sortida
1, perquè un sistema d'avisos ho pugui detectar.
Solucions
Solució 1
// src/entorn.js
// Diagnostic de l'entorn d'execucio en forma de taula.
const memoria = process.memoryUsage();
const parametres = process.argv.slice(2);
const dades = [
{ Dada: 'Versio de Node', Valor: process.version },
{ Dada: 'Plataforma', Valor: process.platform },
{ Dada: 'Arquitectura', Valor: process.arch },
{ Dada: 'Directori', Valor: process.cwd() },
{ Dada: 'Arguments', Valor: parametres.length },
{ Dada: 'Heap usat (MB)', Valor: Math.round(memoria.heapUsed / 1024 / 1024) }
];
console.table(dades);Solució 2
// --- Filtre per preu maxim ---
// Busquem un parametre amb la forma --max=NNNN
const parametreMax = parametres.find((param) => param.startsWith('--max='));
if (parametreMax) {
// Tot el que hi ha despres del signe "=" es el valor.
const valorText = parametreMax.split('=')[1];
const preuMaxim = Number(valorText);
// Number('abc') retorna NaN; Number('') retorna 0, que tampoc no val aqui.
if (!Number.isInteger(preuMaxim) || preuMaxim <= 0) {
console.error(`Error: valor invalid a --max ("${valorText}").`);
console.error('Us: node src/cataleg.js [sala] [--max=CENTIMS] [--taula]');
process.exit(2); // 2 = us incorrecte
}
esdevenimentsMostrats = esdevenimentsMostrats.filter((esdeveniment) =>
// some() retorna true si ALMENYS una sessio compleix la condicio.
esdeveniment.sessions.some((sessio) => sessio.preuCentims <= preuMaxim)
);
}Aquest bloc s'ha de col·locar després del filtre de sala, perquè tots dos es combinin: cada filtre redueix el resultat de l'anterior.
node src/cataleg.js --max=2000 # Noche de Monologos (1800 i 1500)
node src/cataleg.js "Sala Boveda" --max=1600 # Nomes per la sessio de 1500
node src/cataleg.js --max=abc # Error, codi de sortida 2Solució 3
// src/alerta-aforament.js
// Llista les sessions amb venda baixa per llancar accions de promocio.
const cataleg = require('./cataleg-dades.js'); // (veure nota al final)
const LLINDAR_PERCENTATGE = 20;
const enRisc = [];
for (const esdeveniment of cataleg) {
for (const sessio of esdeveniment.sessions) {
const percentatge = Math.round((sessio.venudes / sessio.aforament) * 100);
if (percentatge < LLINDAR_PERCENTATGE) {
enRisc.push({ esdeveniment, sessio, percentatge });
}
}
}
if (enRisc.length === 0) {
console.log('Sense sessions en risc');
process.exitCode = 0;
} else {
for (const element of enRisc) {
console.log(
`${element.esdeveniment.id} | ${element.sessio.id} | ` +
`${formatarData(element.sessio.dataHora)} | ${element.percentatge}% venut`
);
}
// Codi diferent de 0 perque un sistema d'avisos ho detecti.
process.exitCode = 1;
}Sortida esperada amb les nostres dades:
Nota sobre el require de la primera línia: perquè aquest segon script faci servir les mateixes dades caldria exportar-les des d'un fitxer comú. Encara no hem vist com fer-ho —és el tema de Mòduls CommonJS i require()—, així que de moment copia l'array cataleg i la funció formatarData dins de src/alerta-aforament.js. Que aquesta duplicació et resulti incòmoda és precisament el motiu pel qual existeixen els mòduls.
Conclusió
Has escrit i executat el teu primer programa real en Node.js. Pel camí has vist que JavaScript al servidor no té window ni document, però sí process, l'objecte que et connecta amb el sistema operatiu: arguments, entorn, directori de treball, memòria i codi de sortida.
Has construït src/cataleg.js amb els tres esdeveniments fundacionals d'Escena Viva —el Concierto de Otoño al Teatro Almendra, la Noche de Monólogos a la Sala Bóveda i el Festival de Jazz de Primavera a l'Auditorio Ribera—, l'has formatat amb plantilles de cadena i console.table, l'has filtrat amb process.argv i has après a separar les dades (stdout) dels diagnòstics (stderr), tancant amb un codi de sortida coherent. També saps llegir un SyntaxError sense espantar-te: fitxer, línia, token i a mirar cap amunt.
Tot això ho has fet editant un fitxer, desant-lo i tornant-lo a executar. Hi ha una manera molt més àgil de provar idees soltes —una expressió, una transformació del catàleg, un dubte sobre com es comporta un mètode— sense aquest cicle de desar i executar. A la lliçó següent, El REPL de Node.js, aprendràs a fer servir l'intèrpret interactiu per explorar les dades d'Escena Viva en directe i provar transformacions abans d'escriure-les a l'script.
Curs de Node.js: De Principiant a Avançat
Mòdul 1: Introducció a Node.js
- Què és Node.js?
- Instal·lació i Configuració de l'Entorn
- El Teu Primer Programa en Node.js
- El REPL de Node.js
- JavaScript Modern per a Node.js
- El Projecte del Curs: la Plataforma Escena Viva
Mòdul 2: Conceptes Bàsics
- Arquitectura de Node.js
- El Bucle d'Esdeveniments (Event Loop)
- Callbacks i Programació Asíncrona
- Promeses i async/await
- Esdeveniments i EventEmitter
- Mòduls CommonJS i require()
- Mòduls ES i Interoperabilitat
Mòdul 3: Sistema de Fitxers i E/S
- Lectura i Escriptura de Fitxers
- El Mòdul fs a Fons
- Rutes Multiplataforma amb el Mòdul path
- Treballant amb Streams
- Streams de Transformació i pipeline
- Buffers i Dades Binàries
Mòdul 4: HTTP i Servidors Web
- Creant un Servidor HTTP Simple
- Gestió de Sol·licituds i Respostes
- Enrutament Manual
- Servint Fitxers Estàtics
- Rebent Dades: Cossos de Petició i JSON
- Consumint APIs Externes des de Node.js
Mòdul 5: NPM i Gestió de Paquets
- Introducció a NPM i package.json
- Instal·lació i Ús de Paquets
- Versionat Semàntic i package-lock
- Scripts d'npm i Automatització del Projecte
- Creació i Publicació de Paquets
- Seguretat i Manteniment de Dependències
Mòdul 6: Framework Express.js
- Introducció a Express.js
- Configuració d'una Aplicació Express
- Enrutament a Express
- Middleware
- Middleware de Tercers Essencials
- Validació de Dades d'Entrada
- Gestió d'Errors
Mòdul 7: Bases de Dades i ORMs
- Introducció a les Bases de Dades
- Usant MongoDB amb Mongoose
- Operacions CRUD
- Relacions, Poblat i Consultes Avançades
- Usant Bases de Dades SQL amb Sequelize
- Migracions, Transaccions i Dades de Prova
Mòdul 8: Autenticació i Autorització
- Introducció a l'Autenticació
- Registre d'Usuaris i Hash de Contrasenyes
- Sessions i Galetes amb Passport.js
- Autenticació amb JWT
- Control d'Accés Basat en Rols
- Bones Pràctiques de Seguretat en APIs
Mòdul 9: Proves i Depuració
- Introducció a les Proves
- Proves Unitàries amb Mocha i Chai
- Dobles de Prova amb Sinon
- Proves d'Integració
- Cobertura i Automatització de les Proves
- Depuració d'Aplicacions Node.js
Mòdul 10: Temes Avançats
- El Mòdul Cluster
- Fils de Treball (Worker Threads)
- Memòria Cau i Cues de Treball amb Redis
- Optimització del Rendiment
- Construcció d'APIs RESTful
- GraphQL amb Node.js
Mòdul 11: Desplegament i DevOps
- Configuració i Variables d'Entorn
- Registre i Monitoratge en Producció
- Usant PM2 per a la Gestió de Processos
- Empaquetatge amb Docker
- Desplegant a Heroku i Altres PaaS
- Integració i Desplegament Continus
