Node.js — Cheat Sheet

Tag: nodejs, backend, javascript, event-loop, v8, async

Livello: intermedio

TL;DR: Runtime environment per eseguire JavaScript lato server, basato sul motore V8. Utilizza un modello I/O non bloccante e asincrono, ideale per applicazioni scalabili.

Concetti chiave

Architettura single-threaded con Event Loop che gestisce richieste concorrenti in modo asincrono.

Basato sul motore V8 di Google Chrome, compila JavaScript in codice macchina nativo.

Le operazioni di I/O non bloccanti (database, rete, file system) prevengono il blocco del thread principale delegandole a libuv.

La gestione dei moduli avviene storicamente tramite CommonJS (require()) e più recentemente con ES Modules (import).

Il file package.json definisce le dipendenze, gli script e i metadati del progetto (tramite npm, pnpm o yarn).

EventEmitter è il modulo core per implementare l'architettura event-driven (scatenare e ascoltare eventi custom).

Gli Stream (Readable, Writable, Duplex, Transform) gestiscono flussi di dati sequenziali, essenziali per manipolare file di grandi dimensioni con bassa memoria.

I Worker Threads permettono di eseguire calcoli CPU-intensive in parallelo senza bloccare l'Event Loop principale.

Domande tipiche e risposte pronte

Q: How does Node.js handle concurrency despite being single-threaded?R: Sfrutto l'Event Loop e le API asincrone. Le operazioni pesanti di I/O vengono relegate al kernel del sistema operativo tramite libuv, lasciando libero il thread principale.

Q: What is the difference between process.nextTick() and setImmediate()?R: process.nextTick() ha la priorità massima e viene eseguito subito dopo l'operazione corrente, prima che l'Event Loop avanzi. setImmediate() si accoda per il prossimo ciclo dell'Event Loop.

Q: How do you avoid callback hell?R: Uso costantemente Promises e la sintassi async/await. Strutturo il codice in funzioni piccole e modulari per mantenere una gerarchia piatta e leggibile.

Q: What is the purpose of Buffer in Node.js?R: Lo uso per gestire direttamente i dati binari (raw memory allocation). È fondamentale quando si lavora con stream, file system o protocolli di rete TCP.

Insidie e errori comuni

Bloccare l'Event Loop con operazioni sincrone (es. fs.readFileSync o algoritmi pesanti), abbattendo le performance generali.

Dimenticare di gestire le Promise respinte, scatenando unhandledRejection e rischiando crash inaspettati dell'app.

Memory leak derivanti da accumulo di event listener non rimossi (es. EventEmitter.on senza removeListener).

Affidarsi a variabili globali per lo stato dell'applicazione, causando collisioni e comportamenti anomali sotto alto traffico.

Snippet e comandiJavaScript

// Server HTTP base nativo
const http = require('http');

const server = http.createServer((req, res) => {
  res.statusCode = 200;
  res.setHeader('Content-Type', 'application/json');
  res.end(JSON.stringify({ message: 'Hello from Node.js' }));
});

server.listen(3000, () => {
  console.log('Server in ascolto sulla porta 3000');
});

JavaScript

// Utilizzo di fs.promises con async/await e catch
const fs = require('fs').promises;

async function readConfigFile() {
  try {
    const data = await fs.readFile('./config.json', 'utf8');
    return JSON.parse(data);
  } catch (error) {
    console.error('Errore lettura config:', error.message);
    throw error;
  }
}

Bash

# Inizializzare un progetto e installare pacchetti
npm init -y
npm install express dotenv
npm install --save-dev nodemon jest

Da ripassare

[ ] Ordine esatto di esecuzione delle code nell'Event Loop (Timers, Pending, Idle, Poll, Check, Close).

[ ] Implementazione e differenze specifiche tra i vari tipi di Stream (Duplex vs Transform).

[ ] Profilazione della memoria e rilevamento dei memory leak in Node.js (V8 heap snapshot).

Jarvis Interviews
Jarvis