Categorie
Javascript Programmazione

{JS} Istruzioni async e await – Gestione funzioni asincrone

Istruzioni async e await

La coppia di parole chiave async/await consenteno la scrittura di codice asincrono pur mantenendo una struttura di codice tipico della programmazione sincrona.

Si basano sul medesimo meccanismo delle Promises e propongono un nuovo meccanismo di gestione di operazioni asincrone semplificandone la sintassi.

async

La parola chiave async può essere messa prima di una funzione:

async function miaFunzione(){
return 1;
}

La parola “async” indica che la funzione ritorna sempre una promise.

async function miaFunzione(){
return 1;
}

miaFunzione()
.then(function(result){
    alert(result);}
);

Async fa in modo che la funzione ritorni una promise e che “avvolga” (wraps) le non-promise al suo interno.

await

La parola chiave, await, funziona solo nelle funzioni async.
Abbiamo detto che async/await si basa sul meccanismo delle Promise e di conseguenza sono compatibili con custom-promise e con qualsiasi API che utilizza le Promise (es. Fetch)

Prendiamo il seguente esempio:

async function miaFunzione(){

setTimeout(function(){
  var risultato = "eseguito";
},2000);

return risultato;
}

miaFunzione()
.then(function(result){
    alert(result);}
);

In questo esempio abbiamo volutamente ritardare l’esecuzione mediante “.setTimeout()”, simulando una elaborazione impegnativa.
Nel momento in cui utilizziamo la funzione “miaFunzione()”, che ricordiamo essere una funzione-promise asincrona, ci sarà restituito il seguente errore:

Uncaught (in promise) ReferenceError: risultato is not defined

Questo perché la promise “miaFunzione()” richiese il risultato prima che .setTimeout() abbia restituito il risultato.

Prima di procedere e’ bene ricordarci che await è utilizzabile solo con funzioni asincrone unicamente con funzioni dichiarate “async fucntion..”, Promise, Fetch ecc.
L’esempio riportato qui sopra è utilizzato unicamente per far comprendere il problema relativo al ritardo della risposta.

Await ci risolve questo tipo di problematiche, per comprendere al meglio il suo funzionamento proviamo con una custom-promise che rappresenta una funzione con promise asincrona:

async function miaFunzione() {

var promise = new Promise(function(resolve, reject){
  setTimeout(function(){
  resolve("eseguito");
},2000);
});

var risultato = await promise; 
return risultato;

}

miaFunzione()
.then(function(result){
    alert(result);}
);

La parola chiave await fa attendere JavaScript tutto il tempo necessario per l’elaborazione della promise contenuta nella variabile “promise”.

Potremo ancora meglio comprendere il funzionamento di await con il seguente metodo dove utilizzeremo l’API Fetch:

sync function mostraUtente() {

// legge il nostro file JSON
  var response = await fetch('/user.json');
  var user = await response.json();

// legge l'utente GitHub
  var githubResponse = await fetch(`https://api.github.com/users/${user.name}`);
  var githubUser = await githubResponse.json();

  return githubUser;
}

mostraUtente();
.then(function(result){
    console.log(result);
});

Potremmo banalmente tradurre “await” come “prima di fare questo aspetta questo”; come è evidenta dall’esempio abbiamo la possibilità di creare delle molteplici e concatenate situazione di attesa.

Per farlo, e per poterle intercettare/richiamare/concatenare procediamo con il memorizzare i vari “processi” del nostro esecutivo all’interno di variabili.

try e catch

Possiamo inoltre utilizzare le istruzioni try e catch assime a async e await; con il blocco try/catch possiamo intercettare eventuali eccezioni:

async function getUtente(userId) {
    try {
       var response = await fetch("/utente/" + userId);
       console.log(response);
    } catch(error) {
       console.log("Si è verificato un errore!");
    }
 }

Promise.all

Ciascuna operazione asincrona scatenata all’interno della “async function” viene eseguita una dopo l’altra; le operazioni asincrone quindi non avvengono in parallelo, ma sequenzialmente ed avranno un impatto sulle prestazioni dell’applicazione.

Nel caso di molteplici chiamate HTTP eseguite con Fetch queste potrebbero richiedere impegnative risorse; ma, essendo “async/await ” compatibile con le promise, possiamo beneficio dall’esecuzione parallela utilizzare il metodo Promise.all():

sync function getBlogAndPhoto(userId) {
    try {
       let utente = await fetch("/utente/" + userId);
       let result = await Promise.all([
          fetch("/blog/" + utente.blogId),
          fetch("/photo/" + utente.albumId)
       ]);
       return {
          utente,
          blog: result[0],
          foto: result[1]
       };
    } catch (e) {
       console.log("Si è verificato un errore!")
    }
 }

Il metodo “Promise.all()” accetta un array di “promises” e ne restituisce uno contenente tutti risultati.
Queste operazioni saranno eseguite parallelamente.

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *