Fetch API in JavaScript: usare <strong>Promise.all</strong> per chiamate HTTP parallele

by Anastasia P.
SHARE
Fetch API in JavaScript: usare <strong>Promise.all</strong> per chiamate HTTP parallele
© Guida-HTML5.it

Introduzione

Quando lavori con la Fetch API, spesso non devi fare una sola richiesta HTTP, ma più chiamate nello stesso momento. Un caso tipico è una dashboard che deve caricare utente, notifiche e statistiche in parallelo, oppure una pagina prodotto che recupera dati da più endpoint contemporaneamente.

In questi scenari, Promise.all è uno strumento molto utile: ti permette di avviare più richieste insieme e aspettare che tutte siano concluse prima di proseguire. Il vantaggio principale è il tempo di risposta complessivo, che in genere è molto più basso rispetto a eseguire le richieste una dopo l’altra.

In questo tutorial vedremo come usare Promise.all con fetch() in modo pratico, come gestire le risposte, come leggere i dati JSON e quali accorgimenti adottare per evitare errori comuni.

Codice completo

// Esempio: caricamento parallelo di più risorse con Fetch API e Promise.all

async function caricaDashboard() {
  try {
    // Avvio simultaneo di tre richieste HTTP
    const [utenteResponse, notificheResponse, statisticheResponse] = await Promise.all([
      fetch(´https://jsonplaceholder.typicode.com/users/1´),
      fetch(´https://jsonplaceholder.typicode.com/posts?userId=1´),
      fetch(´https://jsonplaceholder.typicode.com/todos?userId=1´)
    ]);

    // Verifica dello stato HTTP di ogni risposta
    if (!utenteResponse.ok) {
      throw new Error(´Errore nel caricamento dei dati utente´);
    }

    if (!notificheResponse.ok) {
      throw new Error(´Errore nel caricamento delle notifiche´);
    }

    if (!statisticheResponse.ok) {
      throw new Error(´Errore nel caricamento delle statistiche´);
    }

    // Parsing JSON in parallelo
    const [utente, notifiche, statistiche] = await Promise.all([
      utenteResponse.json(),
      notificheResponse.json(),
      statisticheResponse.json()
    ]);

    // Uso dei dati
    console.log(´Utente:´, utente);
    console.log(´Notifiche:´, notifiche);
    console.log(´Statistiche:´, statistiche);

    // Esempio di rendering semplice
    document.querySelector(´#app´).innerHTML = `
      

${utente.name}

Email: ${utente.email}

Numero notifiche: ${notifiche.length}

Numero attività: ${statistiche.length}

`; } catch (error) { console.error(´Errore durante il caricamento della dashboard:´, error); document.querySelector(´#app´).innerHTML = `

Impossibile caricare i dati al momento.

`; } } // Avvio caricaDashboard();

Spiegazione

Il cuore di questo approccio è la combinazione tra fetch() e Promise.all.

1. Fetch restituisce una Promise

Ogni chiamata a fetch() restituisce una Promise che si risolve quando la risposta HTTP arriva dal server. Questo significa che puoi raccogliere più Promise in un array e passarle a Promise.all().

2. Promise.all avvia tutto in parallelo

Quando scrivi:

Promise.all([
  fetch(url1),
  fetch(url2),
  fetch(url3)
])

le tre richieste partono quasi nello stesso momento. Non aspetti che la prima finisca per iniziare la seconda. Questo è il punto forte del parallelismo: riduci i tempi morti.

3. La destrutturazione rende il codice leggibile

Nel codice abbiamo usato:

const [utenteResponse, notificheResponse, statisticheResponse] = await Promise.all(...)

Questa sintassi rende chiaro quale risposta corrisponde a quale richiesta. È una buona pratica rispetto a gestire array con indici poco leggibili.

4. Controllare response.ok è fondamentale

Un punto spesso sottovalutato: fetch() non considera automaticamente errore una risposta HTTP con codice 404 o 500. La Promise può comunque risolversi, ma la risposta avrà ok === false. Per questo devi controllare ogni risposta prima di fare json().

5. Parsare JSON con un secondo Promise.all

Anche la conversione in JSON può essere eseguita in parallelo. Dopo aver verificato le risposte, puoi chiamare:

await Promise.all([
  utenteResponse.json(),
  notificheResponse.json(),
  statisticheResponse.json()
])

È una soluzione elegante e coerente, soprattutto quando le risposte sono indipendenti tra loro.

6. Gestione degli errori con try/catch

Se una delle richieste fallisce, Promise.all interrompe la catena e va nel blocco catch. Questo comportamento è utile perché ti consente di intercettare subito il problema. Tuttavia, se vuoi gestire errori separati per ogni richiesta, potresti valutare alternative come Promise.allSettled().

Best practice

  • Usa Promise.all solo per richieste indipendenti: se una richiesta dipende dal risultato di un’altra, eseguirle in parallelo non ha senso.
  • Controlla sempre response.ok: una risposta HTTP non valida non genera automaticamente un errore in fetch.
  • Usa nomi descrittivi per le variabili, così il codice resta comprensibile anche quando le richieste aumentano.
  • Non abusare del parallelismo: troppe richieste insieme possono sovraccaricare il server o peggiorare le prestazioni del client.
  • Valuta Promise.allSettled se vuoi mostrare dati parziali anche quando una richiesta fallisce.
  • Gestisci il rendering in modo progressivo: se la UI è complessa, mostra uno stato di caricamento fino alla fine delle richieste.
  • Evita di parsare JSON prima del controllo dello stato: in caso di errore HTTP, il body potrebbe non contenere un JSON valido.

Quando usare Promise.allSettled al posto di Promise.all

Se stai costruendo una pagina dove alcuni dati sono opzionali, Promise.allSettled() può essere più adatto. A differenza di Promise.all(), non interrompe tutto al primo errore. Ti restituisce invece lo stato di ogni richiesta, permettendoti di decidere cosa mostrare all’utente.

Ad esempio, se le statistiche non sono disponibili ma i dati utente sì, puoi comunque mostrare la pagina senza bloccarla completamente.

Riepilogo

Usare Promise.all con la Fetch API è una tecnica semplice ma molto potente. Ti permette di:

  • eseguire più richieste HTTP in parallelo;
  • ridurre i tempi di caricamento complessivi;
  • scrivere codice più ordinato e leggibile;
  • gestire in modo centralizzato gli errori.

Il flusso ideale è questo: avvii tutte le richieste con fetch(), aspetti la loro conclusione con Promise.all(), controlli response.ok, converti i dati con .json() e poi aggiorni l’interfaccia. È una soluzione molto comune nelle applicazioni moderne, soprattutto quando la pagina dipende da più endpoint REST.

Approfondisci con risorse ufficiali

  • MDN Web Docs - Fetch API: documentazione completa su fetch() e le risposte HTTP.
  • MDN Web Docs - Promise.all(): spiegazione dettagliata del comportamento delle Promise in parallelo.
  • MDN Web Docs - Response: utile per capire proprietà come ok, status e metodi come json().
  • WHATWG Fetch Standard: specifica ufficiale del comportamento della Fetch API nel browser.

SHARE