JavaScript asincrono con callback: gestire operazioni in sequenza

by Anastasia P.
SHARE
JavaScript asincrono con callback: gestire operazioni in sequenza
© Guida-HTML5.it

Introduzione

Le callback sono una delle basi della programmazione asincrona in JavaScript. In pratica, una callback è una funzione passata come argomento a un’altra funzione, che verrà eseguita in un secondo momento. Questo approccio è molto utile quando un’operazione richiede tempo, come leggere un file, interrogare un’API o attendere un timer.

Un sotto-argomento spesso molto pratico, ma meno discusso rispetto ai classici esempi di errore o eventi, è la gestione di operazioni in sequenza con callback. In altre parole: come eseguire più attività asincrone una dopo l’altra, passando il risultato di una alla successiva.

Questo scenario è comune in applicazioni reali. Per esempio:

  • caricare i dati di un utente;
  • usare il suo ID per recuperare gli ordini;
  • infine calcolare un riepilogo finale.

Con le callback, puoi orchestrare questo flusso senza bloccare il programma, mantenendo il codice compatibile con ambienti o librerie che usano ancora questo stile.

Codice completo

// Simuliamo tre operazioni asincrone in sequenza:
// 1) recupero utente
// 2) recupero ordini dell´utente
// 3) calcolo del totale speso

function recuperaUtente(idUtente, callback) {
  setTimeout(() => {
    const utente = {
      id: idUtente,
      nome: "Giulia",
      attivo: true
    };

    console.log("Utente recuperato:", utente);
    callback(null, utente);
  }, 1000);
}

function recuperaOrdini(idUtente, callback) {
  setTimeout(() => {
    const ordini = [
      { id: 1, importo: 29.90 },
      { id: 2, importo: 15.50 },
      { id: 3, importo: 42.00 }
    ];

    console.log("Ordini recuperati per utente", idUtente);
    callback(null, ordini);
  }, 1000);
}

function calcolaTotale(ordini, callback) {
  setTimeout(() => {
    const totale = ordini.reduce((somma, ordine) => somma + ordine.importo, 0);
    callback(null, totale);
  }, 500);
}

// Esecuzione in sequenza con callback annidate
recuperaUtente(101, (erroreUtente, utente) => {
  if (erroreUtente) {
    console.error("Errore nel recupero utente:", erroreUtente);
    return;
  }

  recuperaOrdini(utente.id, (erroreOrdini, ordini) => {
    if (erroreOrdini) {
      console.error("Errore nel recupero ordini:", erroreOrdini);
      return;
    }

    calcolaTotale(ordini, (erroreTotale, totale) => {
      if (erroreTotale) {
        console.error("Errore nel calcolo totale:", erroreTotale);
        return;
      }

      console.log(`Totale speso da ${utente.nome}: €${totale.toFixed(2)}`);
    });
  });
});

Spiegazione

Nel codice sopra abbiamo tre funzioni asincrone simulate con setTimeout. Ogni funzione riceve una callback che viene chiamata al termine dell’operazione.

1. recuperaUtente

Questa funzione simula il recupero di un utente da un database o da una API. Dopo un secondo, costruisce un oggetto utente e lo passa alla callback.

callback(null, utente);

Il primo argomento è null perché non c’è errore. Questa è una convenzione molto comune nelle callback di stile Node.js: primo parametro = errore, secondo parametro = risultato.

2. recuperaOrdini

Una volta ottenuto l’utente, usiamo il suo id per recuperare gli ordini associati. Questo passaggio mostra il vero valore delle callback in sequenza: il risultato di una funzione diventa l’input della successiva.

3. calcolaTotale

Infine, elaboriamo i dati recuperati. In questo caso sommiamo gli importi degli ordini con reduce e restituiamo il totale alla callback.

Perché il flusso è annidato?

Ogni operazione dipende dal risultato della precedente. Per questo il codice è organizzato in blocchi annidati. Questo approccio funziona, ma va usato con attenzione: se la sequenza cresce, il codice può diventare difficile da leggere e mantenere, dando origine al cosiddetto callback hell.

Quando usare questo pattern

La sequenza con callback è utile quando:

  • stai lavorando con API che accettano solo callback;
  • devi mantenere compatibilità con codice legacy;
  • vuoi comprendere bene la logica asincrona di base;
  • hai una pipeline semplice di operazioni dipendenti tra loro.

Best practice

Le callback sono potenti, ma per usarle bene conviene seguire alcune regole pratiche.

  • Segui una convenzione coerente sugli argomenti
    Usa sempre (errore, risultato) quando possibile. Questo rende il codice più prevedibile e facile da integrare.
  • Gestisci subito gli errori
    Se ricevi un errore, interrompi il flusso con return. Eviti così di eseguire codice con dati non validi.
  • Evita annidamenti eccessivi
    Se la sequenza diventa lunga, valuta di estrarre le funzioni in blocchi separati oppure di passare a Promise o async/await.
  • Nomina bene le funzioni
    Nomi come recuperaUtente, recuperaOrdini e calcolaTotale rendono il flusso più chiaro rispetto a nomi generici.
  • Non mescolare callback e logica sincrona confusa
    Mantieni ogni funzione focalizzata su un solo compito: leggere, trasformare o restituire dati.
  • Usa callback per l’orchestrazione, non per tutto
    Se devi solo trasformare dati in memoria, una funzione normale è spesso più semplice. Le callback servono davvero quando c’è asincronia o deferimento dell’esecuzione.

Riepilogo

Le callback sono uno strumento fondamentale della programmazione asincrona in JavaScript. In particolare, sono molto utili per eseguire operazioni in sequenza, passando il risultato di un passaggio al successivo.

In questo tutorial hai visto come:

  • definire funzioni asincrone che ricevono una callback;
  • passare dati tra operazioni successive;
  • gestire una sequenza di task dipendenti;
  • scrivere codice più leggibile usando la convenzione errore/risultato.

Anche se oggi molte applicazioni moderne preferiscono Promise e async/await, capire bene le callback resta essenziale. Ti aiuta a leggere codice legacy, a comprendere il comportamento asincrono di JavaScript e a riconoscere i limiti dei flussi troppo annidati.

Approfondisci con risorse ufficiali

SHARE