W3docs

JavaScript async/await

Impara JavaScript async/await: come le funzioni async restituiscono promise, come funziona await, gestione errori con try/catch, esecuzione sequenziale vs parallela con Promise.all, top-level await e le insidie comuni.

La sintassi async/await è il modo moderno e leggibile per lavorare con il codice asincrono in JavaScript. È costruita direttamente sopra le promiseasync/await non le sostituisce, offre una sintassi più pulita per consumarle. Invece di concatenare callback .then(), si scrive codice che si legge dall'alto verso il basso come un normale codice sincrono, mentre il motore gestisce l'attesa in background.

Questo capitolo tratta cosa restituiscono le funzioni async, come await sospende l'esecuzione, la gestione degli errori con try...catch, l'esecuzione sequenziale rispetto a quella parallela, il await a livello superiore nei moduli e le insidie in cui incorrono la maggior parte degli sviluppatori.

Le funzioni async restituiscono sempre una promise

Contrassegnare una funzione con async fa due cose: permette di usare await nel corpo della funzione e garantisce che la funzione restituisca una promise. Qualsiasi valore si return diventa il valore risolto di quella promise; se si fa throw, la promise viene rigettata.

javascript— editable

Poiché il valore restituito è una promise, chi la chiama deve comunque usare await (o .then()) per leggere il valore effettivo. Un errore comune per i principianti è aspettarsi che greet() restituisca direttamente 'Hello'.

await sospende fino a quando la promise non si risolve

L'operatore await può essere usato solo all'interno di una funzione async (o al livello superiore di un modulo — vedi sotto). Sospende la funzione finché la promise a destra non si risolve: in caso di successo restituisce il valore risolto, in caso di rigetto lancia il motivo del rigetto come eccezione.

È fondamentale notare che await non blocca l'intero programma. Sospende solo la funzione async corrente; il resto del codice e l'event loop continuano a girare.

javascript— editable

Si può usare await con qualsiasi valore, non solo con una promise. I valori non-promise vengono avvolti e risolti immediatamente, quindi await 5 restituisce semplicemente 5.

Gestione degli errori con try...catch

Uno dei maggiori vantaggi di async/await è che si gestiscono gli errori con lo stesso try...catch già usato per il codice sincrono. Una promise rigettata diventa un'eccezione lanciata al punto di await, che catch può intercettare.

javascript— editable

Se non si intercetta un rigetto, diventa un unhandled promise rejection. Per un approfondimento sui meccanismi lato promise, vedi gestione degli errori con le promise.

Un esempio pratico: recuperare dati e segnalare i fallimenti in modo pulito.

javascript— editable

Nota il controllo esplicito di response.ok: fetch rigetta solo in caso di errore di rete, non per i codici di stato HTTP come 404 o 500, quindi è necessario esaminare la risposta manualmente.

Esecuzione sequenziale vs. parallela

È qui che await viene usato in modo scorretto più spesso. Quando si usa await su operazioni una dopo l'altra, vengono eseguite sequenzialmente — ognuna aspetta che la precedente finisca. Questo è corretto solo quando un'attività successiva dipende dal risultato di una precedente.

Sequenziale (quando le attività dipendono l'una dall'altra)

async function pipeline() {
  const user = await getUser(1);          // step 1
  const posts = await getPosts(user.id);  // needs user.id, so must wait
  return posts;
}

Parallela (quando le attività sono indipendenti)

Se le attività non dipendono l'una dall'altra, aspettarle in sequenza è uno spreco di tempo. Avviale tutte e poi attendi insieme con Promise.all:

javascript— editable

Promise.all rigetta non appena una qualsiasi delle sue promise rigetta. Se invece vuoi aspettare ogni promise indipendentemente da successo o fallimento, usa Promise.allSettled. Vedi l'API promise per la famiglia completa di combinatori.

Top-level await nei moduli

All'interno dei moduli ES (<script type="module"> o file .mjs), è possibile usare await al livello superiore senza racchiuderlo in una funzione async:

// data.mjs — an ES module
const response = await fetch('https://jsonplaceholder.typicode.com/todos/1');
const todo = await response.json();

export { todo };

Questo è comodo per l'inizializzazione dei moduli, ad esempio per caricare la configurazione prima che le esportazioni del modulo siano pronte. Nota che un modulo che usa il top-level await ritarda la valutazione di qualsiasi modulo che lo importa. Il top-level await funziona solo nei moduli — usarlo in uno script classico o in una funzione normale è un errore di sintassi.

Insidie comuni

Non usare await in un ciclo per lavoro indipendente

Usare await all'interno di un ciclo for costringe le iterazioni a girare una alla volta. Se le iterazioni sono indipendenti, questo è inutilmente lento.

javascript— editable

Ricorri a await in un ciclo solo quando ogni iterazione dipende genuinamente da quella precedente, o quando devi limitare la frequenza delle richieste.

Altre insidie

  • forEach ignora le callback async. array.forEach(async ...) non aspetta le promise. Usa un ciclo for...of o Promise.all(array.map(...)) al suo posto.
  • Non dimenticare await. Chiamare una funzione async senza await (o .then()) restituisce una promise in attesa e inghiotte silenziosamente gli errori. I linter spesso segnalano le promise "fluttuanti".
  • fetch non rigetta per errori HTTP. Controlla sempre response.ok, come mostrato sopra.

Conclusione

async/await fa sì che il codice JavaScript asincrono si legga come codice sincrono mantenendo l'event loop libero. Ricorda gli elementi essenziali: ogni funzione async restituisce una promise, await sospende solo la funzione corrente, gli errori fluiscono attraverso try...catch e le attività indipendenti dovrebbero essere eseguite in parallelo con Promise.all invece di aspettarle una per una. Per rafforzare le basi di questa sintassi, consulta le promise e il concatenamento di promise.

Esercizi

Pratica
Qual è la funzione della parola chiave 'async' in JavaScript?
Qual è la funzione della parola chiave 'async' in JavaScript?
Was this page helpful?