Promises: then(), catch(), finally() e gli stati di una Promise
Pending, fulfilled, rejected: il modello che ha sostituito i callback annidati
Una Promise è un oggetto che rappresenta il risultato, non ancora disponibile, di un'operazione asincrona: una richiesta di rete, una lettura da disco, un timer. MDN la definisce come un oggetto che collega codice produttore e codice consumatore, permettendo al secondo di reagire quando il risultato sarà pronto, senza doverlo aspettare fermo.
Una Promise è come lo scontrino che ricevi ordinando qualcosa online. Non hai ancora il pacco in mano, ma hai già in tasca la ricevuta di qualcosa che arriverà: puoi decidere fin da subito cosa fare quando arriverà (aprirlo e usarlo) e cosa fare se l'ordine viene annullato, senza restare piantato davanti alla porta ad aspettare.
1. I tre stati di una Promise
Una Promise nasce sempre nello stato pending (in attesa). Da lì può evolvere in uno solo di questi due stati finali: fulfilled (mantenuta, con un valore) oppure rejected (rifiutata, con un motivo). Una volta raggiunto uno stato finale, la Promise si dice settled e non può più cambiare: non torna indietro a pending, né passa da fulfilled a rejected o viceversa.
2. Creare una Promise
Una nuova Promise si crea con il costruttore new Promise(), passando una funzione che riceve due parametri: resolve, da chiamare quando l'operazione va a buon fine, e reject, da chiamare quando fallisce.
const attendiConferma = new Promise((resolve, reject) => {
setTimeout(() => {
const pagamentoRiuscito = true;
if (pagamentoRiuscito) {
resolve('Ordine confermato');
} else {
reject(new Error('Pagamento rifiutato'));
}
}, 1000);
});
3. then(), catch() e finally(): reagire al risultato
Il metodo then() registra cosa fare quando la Promise viene mantenuta, ricevendo il valore passato a resolve(). Il metodo catch() registra cosa fare quando viene rifiutata, ricevendo il valore passato a reject(). Il metodo finally() viene eseguito comunque, sia in caso di successo sia di fallimento, e non riceve nessun valore: serve tipicamente per operazioni di pulizia, come nascondere un indicatore di caricamento.
attendiConferma
.then((messaggio) => {
console.log(messaggio);
})
.catch((errore) => {
console.error('Qualcosa è andato storto:', errore.message);
})
.finally(() => {
console.log('Richiesta conclusa, in un modo o nell\'altro.');
});
4. Promise chaining: incatenare più passaggi
Ogni chiamata a then() restituisce una nuova Promise, il che permette di incatenare più passaggi asincroni in sequenza, uno dopo l'altro, invece di annidarli uno dentro l'altro come succedeva con i callback.
function recuperaUtente(id) {
return fetch(`/api/utenti/${id}`).then((risposta) => risposta.json());
}
function recuperaOrdini(utente) {
return fetch(`/api/ordini?utente=${utente.id}`).then((risposta) => risposta.json());
}
recuperaUtente(42)
.then((utente) => recuperaOrdini(utente))
.then((ordini) => {
console.log('Ordini trovati:', ordini.length);
})
.catch((errore) => {
console.error('Errore nella catena:', errore.message);
});
Una catena di Promise funziona come una staffetta: ogni corridore (ogni then) prende il testimone dal precedente e lo passa avanti al successivo. Se qualcuno lascia cadere il testimone (un errore), la gara per quel corridore si ferma lì, e il giudice di arrivo (il catch finale) viene avvisato subito, saltando tutti i corridori rimasti.
5. Propagazione degli errori: un solo catch per tutta la catena
Se una Promise in un punto qualsiasi della catena viene rifiutata (per esempio perché fetch() fallisce, o una delle funzioni dentro un then() lancia un errore), l'esecuzione salta tutti i then() successivi e passa direttamente al primo catch() trovato lungo la catena. Per questo, di solito, basta un solo catch() alla fine per intercettare un errore avvenuto in un punto qualunque della sequenza.

In sintesi
Una Promise passa da pending a fulfilled o rejected, e una volta raggiunto lo stato finale non cambia più. then(), catch() e finally() permettono di reagire al risultato senza bloccare il resto del programma, e restituendo sempre una nuova Promise rendono possibile incatenare più passaggi asincroni in sequenza, con un solo punto in cui gestire gli errori di tutta la catena. Nella prossima pillola della serie vedremo come lavorare con più Promise insieme, con Promise.all(), allSettled(), race() e any().
Commenti (0)
Registrati per commentare, fare domande e proporre l'argomento della prossima pillola (oppure accedi se hai già un account).
Nessun commento. Sii il primo a scrivere qualcosa.