In questo capitolo vedremo come migliorare il codice sinora sviluppato utilizzando la funzionalità async/await di ECMAScript 6.
Il problema delle Promise
Sappiamo che una Promise restituisce un risultato nel futuro. L'esito può essere positivo (resolve
, la Promise viene risolta) o negativo (reject
, la Promise viene rigettata).
Si supponga di avere questa funzione:
const delay = () => {
return new Promise(resolve => {
setTimeout( () => { resolve(1); }, 1000);
});
};
Il risultato viene restituito dopo un'attesa di 1 secondo. Questo è uno scenario tipico — attendere un risultato — in un ambiente di produzione con query ad un database. È difficile in questo caso sincronizzare il resto del codice con la nostra funzione.
La soluzione: async / await
La parola chiave async
viene preposta ad una funzione per indicare che il codice al suo interno verrà trattato in modo da "emulare" un codice sincrono utilizzando il costrutto await
posto davanti ad una funzione asincrona.
await
vuol dire letteralmente "attendere, aspettare": quando viene usato questo costrutto, si aspetta che una funzione abbia prodotto un risultato che si può memorizzare in una variabile o restituire come Promise (se è il caso). Per il nostro esempio avremo:
const test = async () => {
let result = await delay(); // 1
return result; // <Promise>
};
test().then(result => {
console.log(result); // 1
});
L'esempio non è ancora completo, la documentazione infatti raccomanda di utilizzare un costrutto try/catch
per intercettare eventuali errori prodotti dal codice asincrono:
const test = async () => {
try {
let result = await delay(); // 1
return result; // <Promise>
} catch(e) {
return e;
}
};
test().then(result => {
console.log(result); // 1
}).catch(err => { console.log(err);});
Riscrivere le route dell'App
La prima route dell'App che possiamo riscrivere utilizzando async/await
è quella relativa al listato dei prodotti:
products: async (req, res) => {
if(req.cookies.authenticated) {
try {
let data = await req.API.products();
res.render('products', {
title: 'Products | WooCommerce Node',
products: data.products
});
} catch(err) {
res.redirect('/dashboard');
}
} else {
res.redirect('/');
}
}
In questo caso generiamo l'output HTML subito dopo aver ottenuto l'elenco dei prodotti tramite la chiamata al metodo specifico delle API di WooCommerce. Essendo il codice all'interno di un blocco try/catch
la gestione degli errori viene semplificata.
L'altra route che possiamo migliorare è quella in cui otteniamo l'elenco delle categorie per popolare la select box del form di inserimento di un nuovo prodotto:
product: async (req, res) => {
if(req.cookies.authenticated) {
try {
let data = await req.API.categories();
res.render('product', {
title: 'New product | WooCommerce Node',
categories: data.product_categories
});
} catch(err) {
res.redirect('/dashboard');
}
} else {
res.redirect('/');
}
}
Noterete come le funzioni di callback non necessarie siano state eliminate tramite l'uso di async/await
.