- Async/await si basa sulla promessa di offrire un codice asincrono più leggibile, più vicino allo stile sincrono tradizionale.
- Le funzioni asincrone restituiscono sempre una promessa e consentono di utilizzare await per mettere in pausa la loro esecuzione senza bloccare il thread principale.
- La gestione degli errori con try/catch e utilità come Promise.all semplifica il controllo degli errori e la combinazione di più operazioni in parallelo.
- L'uso combinato di promesse, async/await e API come fetch è il fondamento dello sviluppo JavaScript moderno orientato alla rete.

La programmazione asincrono in JavaScript è diventato indispensabile nello sviluppo web moderno: richieste API, accesso a databaseLa lettura dei file o qualsiasi operazione che richieda più di un momento dipende da questo per mantenere l'interfaccia in funzione senza problemi. Grazie a promesse, async/await e le API Disponiamo di un set di strumenti molto potenti per controllare tale flusso senza bloccare l'applicazione.
Per anni il modello è stato utilizzato principalmente callback e promesse concatenateche, pur funzionando molto bene, possono sfociare nel famigerato "inferno dei callback" o in infinite catene di .then() y .catch() difficile da seguire. Con l'arrivo di async/await in ECMAScript 2017JavaScript ha fatto un enorme passo avanti in termini di leggibilità, consentendo di scrivere codice asincrono in uno stile quasi identico al codice sincrono tradizionale.
Cos'è la programmazione asincrona in JavaScript e perché è così importante?
La programmazione asincrona È un modo di organizzare il codice in modo che un'attività possa iniziare e il programma possa continuare a eseguire altre cose senza "bloccarsi" in attesa di una risposta. In JavaScript, questo è fondamentale perché il linguaggio viene eseguito, nel browser e in Node.js, su un singolo filo conduttore che affronta sia la logica che l'interfaccia.
Quando lanci un Richiesta HTTP a un'APIQuando si legge un file o si interroga un database, queste operazioni possono richiedere da millisecondi a diversi secondi. Se fossero sincrone, l'utente vedrebbe la pagina bloccata e impossibilitato a interagire. Con il modello asincrono, il motore JavaScript delega queste attività e può continuare a lavorare nel frattempo. disegnare l'interfaccia utente, gestire gli eventi ed eseguire altri script.
In origine, il meccanismo standard per reagire quando un'operazione terminava era quello di passare un funzione di callback come argomento. Quella funzione è stata eseguita in seguito con il risultato o l'errore. Il problema è che, concatenando callback all'interno di altre callback, si verifica il temuto inferno di richiamata: codice con troppa indentazione, difficile da leggere, correggere e manutenere.
Per risolvere parte di questo caos, è apparso quanto segue: prometteche incapsulano il risultato di un'operazione asincrona e consentono di concatenare le azioni insieme .then() e gestire i fallimenti con .catch()Questo era già un grande miglioramento, ma lasciava comunque il codice pieno di callback "mascherate" dietro quei metodi.
Promesse: il fondamento di async/await
Prima di comprendere async/await, è essenziale avere ben chiaro cosa sia un promessa in JavaScriptUna promessa è un oggetto che rappresenta il risultato futuro di un'operazione asincrona: qualcosa che non è ancora accaduto ma che accadrà in seguito, con successo o senza successo.
Un promessa standard può essere trovato in uno dei tre stati ben definiti: in attesa (in attesa di) mentre l'operazione è in corso, completata (soddisfatto) quando finisce bene e produce un valore, oppure viene rifiutato (respinto) quando fallisce e genera un errore. Che stato della promessa determina quali callback verranno eseguiti successivamente.
Quando si crea una promessa utilizzando il costruttore PromiseSi passa una funzione eseguibile che riceve due argomenti: resolve y rejectSe l'operazione va bene, chiami resolve(valor)Se si verifica un problema, si invoca reject(error)Quindi, dall'esterno, puoi usare miPromesa.then() per elaborare il risultato e .catch() per gestire gli errori.
Oltre alle promesse fatte a mano, molte API di linguaggi moderni già Mantengono una promessa fatta in serie.. La funzione fetch()Ad esempio, avvia una richiesta HTTP e restituisce immediatamente una promessa che alla fine verrà risolta con un oggetto. Response o rifiutato in caso di guasto della rete.
Per lavorare con più attività in parallelo, JavaScript offre utilità come Promise.all()Questo metodo accetta un array di promesse e restituisce una nuova promessa che viene risolta solo quando tutte le promesse sono state completate con successo, oppure viene rifiutata se una di esse fallisce. Questo è particolarmente utile quando si desidera combinare dati provenienti da diverse fonti prima di continuare.
Concetti chiave: async, await e modello di errore
La sintassi di async/await è basato sulle promesseNon li sostituisce. Ciò che fa è fornire un modo più comodo e chiaro, più vicino alla programmazione sincrona, per lavorare con loro, riducendo il rumore visivo di .then() incatenato.
La parola chiave async Viene posizionato prima di una funzione per dire al motore JavaScript che la funzione funzionerà in modo asincrono e che, qualunque cosa accada al suo interno, manterrà sempre una promessaAnche se restituisci un valore normale, il motore lo inserirà automaticamente in Promise.resolve(valor).
Da parte sua, la parola riservata await può essere utilizzato solo all'interno di una funzione dichiarata come asyncLa sua funzione è quella di mettere in pausa l'esecuzione all'interno di quella funzione finché la promessa passata non viene soddisfatta. essere risolto o respinto, restituendo direttamente il valore risolto o generando un'eccezione se la promessa termina con un errore.
quando usi await promesa e la promessa si risolve, si ottiene il risultato come se fosse una chiamata sincrona. Se invece la promessa viene rifiutata, A quel punto viene generata un'eccezione., equivalente a fare un throw errorCiò consente il riutilizzo delle stesse strutture di gestione degli errori del codice sincrono, come try..catch.
Inserendo le nostre chiamate asincrone in un blocco try { ... } catch (error) { ... }Possiamo rilevare i casi in cui una qualsiasi delle promesse fallisce, mostrare messaggi appropriati all'utente o prendere decisioni come riprovare, reindirizzare o registrare l'errore su un sistema esterno.
La parola chiave async: funzioni che restituiscono sempre promesse
posto async di fronte a una funzione Ciò ha due conseguenze molto importanti: da un lato, obbliga il valore di ritorno ad essere sempre una promessa; dall'altro, consente l'uso di await all'interno del corpo di quella funzione, il che cambia completamente il modo in cui è strutturato il flusso asincrono.
Se dichiari qualcosa come async function sumar() { return 1; }Anche se può sembrare una funzione normale, ciò che si ottiene in realtà è un funzione che restituisce una promessa precedentemente risolta con il valore 1Al di fuori del tuo sistema, dovrai accedere a quel risultato utilizzando await sumar() oppure con sumar().then() se preferisci lo stile concatenato.
È anche possibile restituire esplicitamente una promessa da una funzione. async, per esempio return Promise.resolve(1);e il comportamento sarà lo stesso. In entrambi i casi, la funzione è allineata al modello di promessa, il che facilita la sua combinazione con altre funzioni e utilità asincrone come Promise.all().
È molto comune che, quando iniziamo, dimentichiamo di contrassegnare una funzione come tale async e tuttavia usiamo await entroIn tale situazione, JavaScript genererà un errore di sintassi che indica che await Questo è valido solo nelle funzioni asincrone (o nei moduli che lo supportano a un livello superiore). Questo messaggio è un promemoria che async y await vanno sempre di pari passo.
Negli ambienti in cui non utilizziamo moduli o non dobbiamo supportare browser più vecchi, esiste un modello diffuso che consiste in racchiudere il codice all'interno di una funzione asincrona autoeseguibile, qualcosa di simile a (async () => { ... })();In questo modo, l'intero blocco rimane all'interno di un contesto asincrono senza "contaminare" lo spazio globale.
Come funziona wait e cosa fa realmente con le promesse
Il vero cambiamento di mentalità avviene con awaitQuando il motore JavaScript incontra const resultado = await algunaPromesa; all'interno di una funzione async, mettere in pausa l'esecuzione di quella funzione in quel punto e ritorna al ciclo degli eventi per continuare a occuparsi di altre attività.
Nel frattempo, la promessa continua il suo corso in modo indipendente. Quando finalmente si risolve, il motore riprende l'esecuzione della funzione subito dopo la riga con await, assegnando alla variabile il valore restituito dalla promessaDal punto di vista di chi legge il codice, sembra una chiamata sincrona che richiede solo un po' più di tempo.
Ciò che è interessante è che questa pausa Non blocca la CPUIl thread principale di JavaScript può elaborare eventi utente, animazioni, altro codice asincrono, ecc. Ecco perché diciamo che await È più un elegante astrazione sintattica sulle promesse di un nuovo modo di eseguire le attività in background.
Se preferisci, puoi immaginare che la combinazione const resultado = await promesa; es promesa.then(valor => { resultado = valor; ... }) di qualcosa di equivalente, ma distribuito in modo lineare, che evita callback annidati e migliora la chiarezza del flusso.
Un dettaglio curioso è che, se ti sposti a await un oggetto che non è una promessa ma ha un metodo .then()Il motore cercherà di trattarlo come se lo fosse. Invocherà che .then() con due funzioni interne di risoluzione e rifiuto molto simili a quelli del costruttore di Promise. In questo modo, await È compatibile con le implementazioni delle promesse di tipo "thenable".
Gestione degli errori con async/await: try/catch e promesse rifiutate
Quando una promessa è rifiutare mentre stai usando awaitL'effetto diretto è che viene generata un'eccezione su quella riga. Dal punto di vista del codice, è come se avessi scritto throw error; proprio dove il await, che fa sì che l'esecuzione salti al blocco catch più vicina.
Ad esempio, se usi const datos = await obtenerDatos(); e la funzione obtenerDatos Restituisce una promessa che termina con un errore; il flusso andrà direttamente al blocco catch (error) il tuo try..catchSe non hai un blocco di cattura attorno ad esso, la promessa implicita che la funzione restituisce async Verrà respinta.
Ciò significa che, sebbene possano esserci ancora delle promesse all'interno, quando si lavora con async/await il modo naturale per gestire gli errori È con try..catchCome in qualsiasi altro codice JavaScript che genera eccezioni, questa unificazione degli stili semplifica notevolmente la logica e riduce la necessità di ricordare schemi diversi a seconda che il codice sia sincrono o asincrono.
Se per errore dimentichi di aggiungere un .catch() alla promessa restituita da una funzione async In caso di errore, l'ambiente visualizzerà un avviso. “promessa non gestita” (rifiuto di promessa non gestitaInoltre, è possibile utilizzare l'evento globale nel browser. unhandledrejection per registrare un gestore che catturi tutti quegli errori e impedisca che passino inosservati.
Quando si combina await con utilità come Promise.all, un singolo errore in una delle promesse sarà propaga la promessa congiunta e alla fine si traduce in un'eccezione che puoi catturare con try..catchIn questo modo, la gestione degli errori nei flussi di lavoro complessi rimane coerente e centralizzata.
Async/await con fetch: chiamate API passo passo
Uno degli usi più comuni di async/await è l'accesso API HTTP che utilizzano la funzione fetch()Questa API restituisce una promessa che si risolve in un oggetto Response, su cui è possibile quindi invocare metodi come .json() o .text()che a loro volta fanno nuove promesse.
Immagina di voler incapsulare la logica della richiesta di dati da un endpoint in una funzione. Se dichiari async function obtenerDatos(), al suo interno puoi attendere la risposta della rete con await fetch(...) e quindi trasformare il corpo in JSON con const datos = await respuesta.json(); senza dover concatenare più .then().
Per assicurarsi che il server abbia risposto correttamente, è comune controllare la proprietà respuesta.okche indica se il codice di stato HTTP è compreso nell'intervallo 200-299. In caso contrario, è possibile generare manualmente un errore con throw new Error('Error en la red');, che causerà il catch catturare la situazione.
Organizzare l'intero flusso all'interno di un try { ... } catch (error) { ... } Ciò rende la funzione asincrona molto più resiliente: qualsiasi problema, sia di rete, di analisi JSON o correlato alla logica, attiverà il blocco di acquisizione in cui è possibile registra l'errore o visualizza un messaggio più intuitivo.
In definitiva, per utilizzare la funzione, è sufficiente chiamarla come qualsiasi altra: obtenerDatos();Ricorda che, essendo asincrono, restituisce una promessa, quindi dall'esterno dovrai scegliere se utilizzarlo. await obtenerDatos() all'interno di un'altra funzione async o gestirlo con .then().catch() se ti trovi in un contesto non asincrono.
Esegui più operazioni in parallelo con Promise.all e async/await
Spesso non si vuole aspettare che una richiesta finisca prima di iniziare la successiva; si è invece interessati a... avviare più operazioni asincrone contemporaneamente e continuare quando hanno finito tutti. Per questo, il metodo Promise.all() si adatta perfettamente.
Supponiamo che tu debba utilizzare due API diverse, ad esempio /datos1 y /datos2e poi unire le informazioni in un unico oggettoInvece di aspettare che il primo sia completato prima di iniziare il secondo, puoi scrivere qualcosa come const [r1, r2] = await Promise.all([fetch(url1), fetch(url2)]); ed entrambe le domande saranno presentate parallelamente.
Una volta ottenute entrambe le risposte, puoi candidarti await su ciascuno di essi per trasformarli in JSON: const d1 = await r1.json(); const d2 = await r2.json();Infine, è molto comune combinare i dati con l'operatore di propagazione: const datosCombinados = { ...d1, ...d2 };, che crea una struttura unica che fonde le proprietà di entrambi.
L'intero blocco dovrebbe essere avvolto in un try..catchperché qualsiasi errore in una delle richieste causerà Promise.all() viene rifiutato. Grazie ad async/await, la gestione di questi tipi di scenari con operazioni simultanee È visivamente semplice ma molto potente in termini di prestazioni.
Questo modello è particolarmente utile quando la tua applicazione web richiede diverse risorse indipendenti prima che una vista possa essere renderizzata: ad esempio, ottenendo contemporaneamente configurazione, dati utente e statistiche di utilizzo, riducendo il tempo di attesa complessivo.
Vantaggi reali di async/await rispetto alle promesse e ai callback “puri”
L'uso di async/await offre una serie di vantaggi pratici Questi vantaggi sono evidenti fin dai primi esempi fino alle applicazioni su larga scala. Il più evidente è la leggibilità: il flusso viene scritto dall'alto verso il basso, senza la necessità di funzioni annidate o concatenate. .then() uno dopo l'altro.
Un altro punto di forza è il manutenibilità del codiceCon blocchi più lineari, è più facile introdurre modifiche, estrarre parti in funzioni ausiliarie o riutilizzare la logica. Questo si traduce direttamente in meno errori e in una curva di apprendimento più fluida per i nuovi arrivati nel progetto.
Gestione degli errori con try..catch invece di multipli .catch() sparpagliato Aiuta a centralizzare la logica di errore. È possibile circondare più await con un singolo blocco e implementare una politica di gestione degli errori coerente, senza perdere i dettagli sulla riga su cui si è verificato il problema.
Dal punto di vista delle prestazioni, async/await non rende il codice "più veloce" di per sé, ma può incoraggiarti a utilizzare modelli come Promise.all() per eseguire attività in parallelo dove in precedenza avresti potuto eseguirle in serie. Il risultato è tempo di attesa totale inferiore per l'utente finale.
Inoltre, async/await è compatibile con le promesse tradizionaliNon è necessario riscrivere tutto il codice per adottarlo. È possibile combinare le funzioni che lo utilizzano. .then() con altri che usano await Nessun problema, il che semplifica la migrazione graduale dei progetti.
Nell'ecosistema moderno, sia nei browser che in Node.js, la maggior parte degli strumenti e delle librerie si basa già su promesse e async/await. Questo rende l'apprendimento di questi concetti non facoltativo, ma essenziale. un requisito per lavorare con JavaScript moderno in progetti professionali.
Tutto questo insieme di idee: promesse, asincrono/attesa, fetch, Promise.allIl try/catch e il glossario dei termini chiave formano una struttura molto solida per la scrittura codice asincrono chiaro, leggibile e robustoPadroneggiandole è possibile creare applicazioni web moderne che rispondono rapidamente, sfruttano al meglio la rete e sono molto più facili da gestire nel tempo.
Scrittore appassionato del mondo dei byte e della tecnologia in generale. Adoro condividere le mie conoscenze attraverso la scrittura, ed è quello che farò in questo blog, mostrarti tutte le cose più interessanti su gadget, software, hardware, tendenze tecnologiche e altro ancora. Il mio obiettivo è aiutarti a navigare nel mondo digitale in modo semplice e divertente.