Le Promise sono considerate una delle novità più interessanti di JavaScript nella versione ES6 (ECMAScript 6), gli sviluppatori che utilizzano questo linguaggio le hanno attese a lungo, ma esattamente in cosa consistono? Qual è la loro sintassi e in che modo è possibile utilizzarle all’interno delle Web Application? Per rispondere a queste domande proviamo a proporne una definizione esauriente e a mostrare un semplice esempio pratico del loro impiego.
Cosa sono le Promise?
Iniziamo col dire che le Promise sono state concepite per rappresentare operazioni incomplete al momento corrente che saranno però complete in futuro; per questo motivo parliamo di un costrutto adottato nel caso di elaborazioni asincrone e differite. Data la loro natura le Promise prevedono tre stati differenti:
- pending, cioè in attesa, che è lo stato iniziale.
- fulfilled, cioè "soddisfatto", che si verifica quando un’operazione ha avuto successo.
- rejected, cioè "respinto", nel caso del fallimento di un’operazione.
Un pending può esitare sia in fulfilled che in rejected, nel primo caso verrà generato un valore, nel secondo avremo una notifica di errore, ecco perché le Promise possono risultare particolarmente utili se usate in associazione ad istruzioni condizionali.
La sintassi delle Promise
A livello sintattico le Promise prevedono un esecutore (executor) a cui passare gli argomenti resolve
e reject
che sono in pratica due funzioni. Quando vengono chiamate esse risolvono o rigettano una Promise, resolve
risolve la Promise, reject
agisce invece in caso di errore; un errore dell’esecutore porta a rigettare la Promise.
new Promise(function(resolve, reject) { ... });
Possiamo quindi affermare che le Promise agiscono su due canali, il primo per la restituzione del risultato, il secondo per gli eventuali errori. Il risultato verrà proposto attraverso la clausola then
, mentre l’errore è gestibile tramite catch
, come nell’esempio seguente:
function asyncFunc() {
return new Promise((resolve, reject) => {
setTimeout(() => {
const a = Math.random();
a > 0.4 ? resolve(a) : reject('impossibile restituire un risultato.')
}, 1)
});
}
for (let x=0; x<5; x++) {
asyncFunc()
.then(a => console.log('Risultato: ' + a))
.catch(a => console.log('Attenzione: ' + a))
}
Il compito della nostra funzione è quello di restituire un valore casuale compreso tra 0.4 e 1, dato che esso verrà generato in un ciclo che ha come condizione di terminazione 5, esso verrà proposto 5 volte. Nel caso in cui il valore sia compreso nell’intervallo previsto avremo il risultato richiesto, diversamente verrà notificata l’impossibilità di restituire un risultato. Potremmo visualizzare per esempio un output del genere:
Risultato: 0.5648408816884605 Risultato: 0.8635538728822045 Risultato: 0.7777550929781212 Risultato: 0.7215696190059968 Risultato: 0.45977562744546674
così come un esito come il seguente:
Risultato: 0.4229606424564949 Risultato: 0.4112983411592879 Risultato: 0.9140842306497625 Attenzione: impossibile restituire un risultato. Attenzione: impossibile restituire un risultato.