Promise
Come abbiamo già visto, fetch crea un oggetto Promise, più precisamente una istanza della classe Promise.
Le promise sono oggetti che vengono utilizzati per eseguire attività che richiedono un certo tempo e che quindi non possono restituire subito un risultato. Quindi per non bloccare l’interfaccia utente della pagina web, la promise costituisce uno strumento per permettere la programmatore di indicare sia l’attività da svolgere sia la callback da eseguire in caso di conclusione che quella da eseguire in caso di errore dell’attività.
Una volta creata la promise, questa mette a disposizione due metodi:
– then(successCallback): questo metodo dopo aver eseguito l’operazione contenuta nella promise mette in coda la funzione passata come parametro (detta success callback)
– catch(errorCallback): indica la funzione che viene invece eseguita se c’è stato un errore.
E’ possibile creare le promise direttamente creando una istanza della classe Promise. Il costruttore riceve come argomento una funzione nella seguente forma:
const promise = new Promise((resolve, reject) => {
try {
... istruzioni da svolgere
resolve(...);
} catch(exception) {
reject(...);
}
);
L’istruzione resolve esegue la successCallback (dopo la then), l’istruzione reject esegue la errorCallback (dopo la catch). Se tutto va bene verrà eseguita la successCallback, altrimenti la errorCallback (non entrambe ovviamente).
Una promise non viene eseguita automaticamente: una volta creata è pronta per essere eseguita ma è sempre necessario eseguirla usando la then (che diventa la resolve). La catch (che diventa la catch) è invece facoltativa.
Vediamo un esempio asincrono in cui creiamo una promise che esegue un setTimeout.
const timeoutPromise = new Promise((resolve, reject) => {
try {
setTimeout(() => {
const value = Math.rand();
resolve(value);
} catch(exception) {
reject();
}
);
timeoutPromise.then((value) => console.log(value)).reject(console.error);
Quando si esegue il then, la promise esegue il codice previsto, e poi schedula la funzione resolve, con il catch invece viene indicata la funzione reject.
Vediamo un altro esempio, molto utile. Con le promise possiamo eliminare il doppio passaggio di risposta di una chiamata fetch quando sappiamo che dobbiamo estrarre un JSON dalla risposta.
const render = (data) => {
... render instructions
}
const createFetch = (url, options) => {
return new Promise((resolve, reject) => {
try {
fetch(url, options)
.then(response => response.json())
.then(data => resolve(data))
} catch (exception) {
reject(exception);
}
});
}
createFetch("www.myservice.com", {}).then(render);
Ipotizzando quindi di avere valorizzati url e options, ed avendo a disposizione una funzione render pronta, possiamo accorpare la doppia then in una unica then.