62 Promise

Le promises sono oggetti che rappresentano un’operazione che non è ancora completata, ma potrebbe esserlo in futuro. Ecco le caratteristiche delle promises:

  • Ci permettono di gestire processi asincroni in modo maggiormente sincrono
  • Rappresentano un valore che possiamo gestire in un futuro
  • Il valore non può essere cambiato da altri handler, in quanto la Promise è immutabile
  • Il valore è sempre disponibile, anche se registriamo l’ handler dopo che la promise è stata risolta

Creare una Promise

Si istanzia l’oggetto Promise a cui si riferisce una funzione predefinita chiamata esecutore che riceve 2 parametri callback:

  1. Uno per risolvere la Promise , chiamato resolve
  2. L’altro per rifiutarla, chiamato reject

Ecco il costrutto dele promises:

let p = Promise(function(resolve, reject) {
 if(condizione) {
  resolve(valori, la promise è andata a buon fine);
 } else {
   reject(ragione del rifiuto);}
});

Stati della Promise

Le promise presentano 3 tipi di stati:

  • Pending : questo è lo stato in cui la promise non è stata ancora ne risolta, ne rigettata, quindi è pendente e non ha ritornato ancora nessun valore
  • Fullfilled: è lo stato in cui viene chiamato il primo parametro della funzione, il resolve. La promise è stata risolta
  • Rejected: è lo stato in cui viene chiamato il secondo metodo, il reject. La promise è stata rifiutata.

Iniziamo a vedere le promises in azione. Creiamo un semplice file HTML vuoto che richiama un file promise.js

<!DOCTYPE html>
<html lang="it">
<head>
    <meta charset="UTF-8">
    <title>Promises</title>
    <script src="promise.js"></script>
</head>
<body>
<h1>Promises</h1>
</body>
</html>

salviamo promise.html e creiamo promise.js lanciando il metodo resolve predefinito nell’oggetto Promise, memorizzandolo in un nuovo oggetto p

let p = Promise.resolve('La Promise è risolta');

Questo vuol dire che noi stiamo risolvendo subito la promise. Quando la promise viene risolta ritorna un valore, nel nostro caso la stringa “La Promise è risolta”.

Fino a questo punto non accade nulla perchè dobbiamo ancora leggere il valore di ritorno della promise. Questa operazione può essere fatta con il metodo then che richiede una funzione la quale riceverà come parametro res che sarà il risultato del resolve della promise

p.then((res) => {
    console.log(res);
});

Nella console del browser riceveremo il risultato del resolve. Il metodo then ha il significato di: ” una volta che la promise è stata risolta esegui la funzione “. Quindi se il resolve è andato a buon fine ritornerà a then il valore  tramite il parametro della funzione (in questo caso abbiamo usato una funzione freccia).

Vediamo ora la situazione del reject commentando il precedente resolve

let r = Promise.reject('La Promise è respinta');

r.then(function (res) {
    console.log(res);
});

Normalmente non sappiamo a priori se la promise andrà a buon fine o meno, il then in questo caso genererà un warning invece di eseguire la funzione, perchè la promise non è stata risola. Bisogna gestire questa situazione utilizzando un metodo che si chiama catch. Con catch possiamo catturare qualunque errore venga restituito dal reject. Concateniamo il metodo catch al then per catturare l’errore

r.then(function (res) {
    console.log(res);
}).catch((erro) => console.log(erro));

a questo punto in console ottengo il valore del reject, catturato come parametro della funzione passata al metodo catch concatenato al metodo then.

Utilizzo di un costruttore

Vediamo ora un secondo modo per istanziare una promise che è la forma presentata a inizio lezione che Istanzia un nuovo oggetto con new . Creiamo un altro file promise-new.js

let p = new Promise(function (resolve,reject) {
    
})

L’ oggetto Promise necessita di una funzione che riceve 2 parametri il resolve se la promise è andata a buon fine o il reject se si verificano problemi. Dentro questa funzione normalmente si fanno tutte le verifiche necessarie, chiamate asincrone, chiamate AJAX e se tutto va a buon fine verrà chiamato il metodo resolve che restituisce un valore, per esempio facciamogli restituire il numero 24

let p = new Promise(function (resolve,reject) {
    resolve(24);
});

ricordatevi che per testarlo bisogna cambiare il nome del file js dentro l’html. Vediamo nel modo analogo di prima il reject con l’ausilio del catch

let r = new Promise(function (resolve,reject) {
    reject('Un errore');
});

r.then(function() { } ).catch((er) => console.log(er));

Sollevare un’eccezione

Un altro modo per catturare un eventuale errore è quello di sollevare un’eccezione tramite il throw la quale sarà catturata nel catch

let r = new Promise(function (resolve,reject) {
    throw new Error('Si è verificato un errore');
});

r.then(function() { } ).catch((er) => console.log(er));

Grazie al throw vengono anche aggiunti altri notice nella console che ci indicano più dettagli sull’errore che si è verificato, oltre a quello scritto da noi.

Con le promise il codice diventa molto più snello, evitando notevoli if annidati e diminuendo le eccezioni da catturare.