W3docs

Concatenazione di Promise in JavaScript

Scopri come funziona la concatenazione di Promise in JavaScript per gestire operazioni asincrone in sequenza con .then(), .catch() e .finally().

La concatenazione di Promise ti permette di eseguire operazioni asincrone una dopo l'altra, dove ogni passaggio inizia solo dopo che il precedente è terminato. Colleghi una sequenza di gestori .then() a una promise, e ogni gestore riceve il risultato del passaggio precedente.

Prima delle promise, sequenziare lavoro asincrono significava annidare callback dentro callback — il famigerato "callback hell" o "pyramid of doom":

queryDatabase('users', (users) => {
  queryDatabase('posts', (posts) => {
    queryDatabase('comments', (comments) => {
      // deeply nested, hard to read, error handling duplicated everywhere
    });
  });
});

La concatenazione appiattisce quella piramide in una sequenza leggibile dall'alto verso il basso, con un unico punto per gestire gli errori. Questa pagina illustra come funziona effettivamente la concatenazione, il bug più comune (un return mancante), il ripristino degli errori e la pulizia. Per la sintassi correlata che si basa sulle promise, vedi JavaScript: async/await.

Come Funziona la Concatenazione: Ogni .then() Restituisce una Nuova Promise

Questo è il meccanismo fondamentale da cui discende tutto il resto. .then() non restituisce la promise originale — restituisce una promise completamente nuova. Il valore a cui si risolve questa nuova promise dipende da ciò che il tuo gestore restituisce:

  • Restituisce un valore semplice → il .then() successivo riceve quel valore.
  • Restituisce una promise → la catena attende che si definisca, e il .then() successivo riceve il suo valore risolto (non la promise stessa).
  • Non restituisce nulla → il .then() successivo riceve undefined.
  • Lancia un errore → la catena salta al .catch() più vicino.

Poiché ogni .then() restituisce una nuova promise, puoi continuare ad aggiungere chiamate .then() e passare un valore lungo la catena:

javascript— editable

Il caso potente è restituire una promise da un gestore. La catena si mette in pausa finché quella promise non si risolve prima di proseguire, che è esattamente il modo in cui si sequenziano operazioni asincrone dipendenti:

Concatenazione di Promise di Base

Considera lo scenario in cui devi interrogare un database e poi usare il risultato di quella query per effettuarne un'altra. Ogni .then() restituisce la promise della query successiva, quindi la catena attende che una query finisca prima di avviarne un'altra:

javascript— editable

Il Bug #1: Dimenticare return (la "catena scollegata")

Questo è il singolo errore più comune nella concatenazione di promise. Se avvii un'operazione asincrona all'interno di un .then() ma dimentichi di restituire la sua promise, la catena non la aspetta — il risultato viene perso e il .then() successivo viene eseguito immediatamente con undefined. La promise interna diventa una catena "scollegata" che viene eseguita per conto proprio.

Nella versione errata qui sotto, queryDatabase('posts') viene chiamata ma la sua promise non viene restituita, quindi il secondo .then() registra undefined invece dei post:

javascript— editable

Aggiungere return riconnette la catena. Ora il secondo .then() attende la query dei post e ne riceve il risultato:

javascript— editable

Suggerimento: le arrow function con corpo a espressione restituiscono automaticamente — .then(r => queryDatabase(r)) restituisce la promise, ma .then(r => { queryDatabase(r); }) (con le parentesi graffe) non lo fa.

Gestione degli Errori nelle Catene

Un singolo .catch() alla fine della catena gestisce qualsiasi errore lanciato — o qualsiasi promise rifiutata — in qualsiasi passaggio precedente. Quando qualcosa fallisce, la catena salta tutti i .then() rimanenti e va direttamente al .catch() successivo.

In questo esempio la prima query viene rifiutata, quindi il .then() viene completamente saltato e il controllo passa al .catch():

javascript— editable

Per uno sguardo più approfondito sui pattern di rifiuto, vedi Gestione degli Errori con le Promise.

.catch() a Metà Catena per il Ripristino

Un .catch() non deve essere necessariamente l'ultimo anello. Posizionato nel mezzo di una catena, può gestire un errore, restituire un valore di fallback e permettere alla catena di continuare. Questa è la differenza tra il ripristino da un fallimento e l'interruzione dell'intera sequenza.

Di seguito, il primo passaggio fallisce, ma un .catch() a metà catena fornisce un valore predefinito e la catena continua:

javascript— editable

Un .catch() a metà catena recupera e riprende; un .catch() terminale è la rete di sicurezza finale per tutto ciò che non è stato recuperato in precedenza.

Pulizia con .finally()

.finally() viene eseguito una volta che la promise si definisce — che si sia risolta o rifiutata. Non riceve argomenti e non cambia il valore che passa attraverso la catena, il che lo rende ideale per la pulizia che deve avvenire in ogni caso: nascondere uno spinner, chiudere una connessione o riabilitare un pulsante.

javascript— editable

Eseguire Promise in Parallelo: Promise.all

Promise.all non è concatenazione — la concatenazione è sequenziale (una dopo l'altra), mentre Promise.all esegue le promise in parallelo e attende che tutte terminino. Usalo quando le operazioni non dipendono l'una dall'altra, quindi non c'è motivo di aspettare che una finisca prima di avviare la successiva.

Riceve un iterabile di promise e restituisce una singola promise che si risolve in un array con i loro risultati, nello stesso ordine dell'input. Qualsiasi valore non-promise nell'array (come 42 qui sotto) viene automaticamente racchiuso in una promise risolta. Se una qualsiasi delle promise di input viene rifiutata, l'intera Promise.all viene rifiutata immediatamente con quell'errore.

javascript— editable

Per Promise.all, Promise.race, Promise.allSettled e gli altri combinatori, vedi la Promise API.

  • Ogni .then() restituisce una promise nuova; la catena si legge dall'alto verso il basso invece di annidarsi.
  • Restituisci i valori per passarli avanti, e restituisci una promise da un gestore per far attendere la catena.
  • Il bug più comune è un return mancante all'interno di .then() — disconnette il lavoro asincrono interno e il passaggio successivo riceve undefined.
  • Un .catch() terminale gestisce gli errori da qualsiasi passaggio precedente; un .catch() a metà catena può recuperare e riprendere.
  • Usa .finally() per la pulizia che deve essere eseguita sia che la catena abbia avuto successo o sia fallita.
  • Usa Promise.all per lavoro indipendente che deve essere eseguito in parallelo — è uno strumento diverso dalla concatenazione sequenziale.
  • Quando ti senti a tuo agio qui, async/await ti offre lo stesso comportamento con una sintassi dall'aspetto sincrono.

Esercitati

Pratica
Qual è lo scopo della Concatenazione di Promise in JavaScript?
Qual è lo scopo della Concatenazione di Promise in JavaScript?
Was this page helpful?