W3docs

Iteratori e Generatori Asincroni in JavaScript

Impara gli iteratori e i generatori asincroni in JavaScript: Symbol.asyncIterator, async function*, for await...of e un esempio di fetch paginata lazy con codice eseguibile.

La programmazione asincrona è un pilastro fondamentale dello sviluppo moderno in JavaScript, che consente agli sviluppatori di scrivere codice non bloccante e concorrente in grado di gestire in modo efficiente attività come richieste di rete, I/O su file e timer. Questa guida tratta gli iteratori asincroni e i generatori asincroni, due funzionalità introdotte in ECMAScript 2018 che permettono di iterare su dati che arrivano nel tempo — un blocco per ogni round-trip di rete, un evento per ogni azione dell'utente — senza bloccare il resto del programma.

Questa pagina presuppone che tu abbia familiarità con gli iterabili, i generatori e le promise. Se qualcuno di questi argomenti è nuovo, leggilo prima.

Comprendere gli Iteratori Asincroni

Cosa sono gli Iteratori Asincroni?

Gli iteratori asincroni sono un tipo speciale di iteratore progettato per gestire flussi di dati asincroni. A differenza degli iteratori tradizionali, che operano in modo sincrono, gli iteratori asincroni consentono agli sviluppatori di iterare su sequenze di valori asincroni, come promise o stream, in modo non bloccante.

Tecnicamente, un object viene considerato un iterabile asincrono se implementa il metodo Symbol.asyncIterator, che restituisce un object iteratore asincrono. Ecco un esempio pratico di implementazione manuale di questa interfaccia su un object personalizzato:

javascript— editable

Iteratori Sincroni vs. Iteratori Asincroni

La differenza tra un iterabile ordinario e uno asincrono si riduce a tre aspetti: il nome del metodo, il tipo restituito da next() e il ciclo utilizzato per consumarlo.

Iterabile sincronoIterabile asincrono
MetodoSymbol.iteratorSymbol.asyncIterator
next() restituisce{ value, done }una Promise di { value, done }
Ciclo di consumofor...offor await...of
Sintassi del generatorefunction*async function*

Poiché nel caso asincrono next() restituisce una Promise, ogni passo del ciclo può attendere un'operazione asincrona — una fetch, un timer, una lettura dal database — prima che venga prodotto il valore successivo. Un semplice for...of non può farlo: si aspetta che value/done siano disponibili immediatamente. Usare for await...of su un iterabile solo sincrono funziona comunque (il motore avvolge i valori in promise già risolte), ma usare un for...of sincrono su un iterabile asincrono non funziona — si itererebbe semplicemente su object Promise in attesa.

Come Usare gli Iteratori Asincroni

Per sfruttare gli iteratori asincroni nel codice JavaScript, è necessario innanzitutto comprenderne i concetti fondamentali e la sintassi. Esploriamo un semplice esempio per illustrare il funzionamento degli iteratori asincroni in pratica:

javascript— editable

In questo esempio definiamo una funzione generatrice asincrona generateNumbers() che produce una sequenza di numeri in modo asincrono. Creiamo quindi un iterabile asincrono dalla funzione generatrice e utilizziamo un ciclo for await...of per iterare sui valori prodotti dall'iteratore asincrono.

Nota: Quando si usa yield con un valore semplice all'interno di una async function*, il metodo next() dell'iteratore restituisce automaticamente una Promise che si risolve in { value: <il tuo valore>, done: false }. È necessario fare yield di una Promise esplicitamente solo se si vuole che il consumatore riceva un object Promise anziché il valore risolto.

Applicazioni nel Mondo Reale degli Iteratori Asincroni

Gli iteratori asincroni trovano ampia applicazione in scenari che coinvolgono l'elaborazione asincrona dei dati, come il recupero di dati da API esterne, la lettura da stream o la gestione di eventi asincroni. La loro versatilità ed efficienza li rende strumenti indispensabili per i moderni sviluppatori JavaScript che desiderano scrivere applicazioni scalabili e reattive.

Esplorare i Generatori JavaScript

Introduzione ai Generatori

I generatori sono una funzionalità potente introdotta in ECMAScript 2015 che consente la creazione di sequenze iterabili con logica di iterazione personalizzata. A differenza delle funzioni tradizionali, che vengono eseguite fino al completamento al momento dell'invocazione, i generatori possono mettere in pausa e riprendere la propria esecuzione, consentendo la valutazione pigra dei valori.

È importante distinguere tra generatori standard e generatori asincroni:

  • Generatori Standard (function*): Producono valori in modo sincrono.
  • Generatori Asincroni (async function*): Restituiscono una Promise da ogni chiamata a next(), consentendo al consumatore di attendere ogni valore utilizzando for await...of.

Sfruttare i Generatori per la Programmazione Asincrona

Uno degli use case più convincenti per i generatori è la programmazione asincrona. Combinando generatori e promise, gli sviluppatori possono creare flussi di lavoro asincroni che sono allo stesso tempo eleganti e facili da ragionare. Ecco un esempio moderno che utilizza un generatore asincrono per recuperare e produrre dati da un server remoto:

javascript— editable

In questo esempio definiamo una funzione generatrice asincrona fetchTodos() che recupera dati in modo asincrono da un'API remota usando la funzione fetch(). Usando await all'interno del generatore e producendo i singoli elementi, possiamo inviare in streaming i risultati direttamente in un ciclo for await...of senza chiamate manuali a .next() o concatenamento di promise.

Fetch Paginata con un Generatore Asincrono

Il pattern che fa brillare i generatori asincroni è la paginazione pigra. Molte API restituiscono i risultati in pagine e richiedono di continuare a richiedere la pagina successiva fino a quando non ce ne sono altre. Un generatore asincrono può nascondere tutta questa gestione contabile: recupera una pagina, produce i suoi elementi uno per uno e richiede la pagina successiva solo quando il consumatore ne ha bisogno. Il chiamante può interrompersi prima — per esempio dopo aver trovato ciò di cui ha bisogno — e non vengono effettuate ulteriori richieste di rete.

javascript— editable

Nota il break: poiché il generatore è pigro, uscire dal ciclo dopo 25 elementi significa che il generatore non richiede mai la pagina 3. Questo è ciò che distingue un generatore asincrono dal recuperare tutto in anticipo in un array — si paga solo per i dati effettivamente utilizzati.

Pattern Avanzati con i Generatori

I generatori offrono una moltitudine di pattern e tecniche avanzati per risolvere problemi di programmazione complessi. Ecco alcuni esempi che mostrano la loro versatilità:

  • Esecuzione Parallela: Avviando più generatori e gestendo le loro promise in modo concorrente, è possibile eseguire più attività asincrone contemporaneamente.
  • Gestione degli Errori: Utilizza blocchi try-catch all'interno dei generatori per gestire in modo elegante le promise rifiutate prodotte durante il processo di iterazione.
  • Pipeline di Dati: Costruisci pipeline di elaborazione dati concatenando generatori tra loro, dove l'output di un generatore funge da input per il successivo.
javascript— editable

Conclusione

In conclusione, gli iteratori asincroni e i generatori sono strumenti indispensabili nell'arsenale del moderno sviluppatore JavaScript. Padroneggiando queste potenti funzionalità, puoi sbloccare nuove dimensioni di espressività ed efficienza nel tuo codice asincrono. Che tu stia costruendo applicazioni web, API lato server o utility da riga di comando, gli iteratori asincroni e i generatori ti consentono di affrontare con facilità complesse sfide asincrone. Inizia oggi stesso a incorporare iteratori asincroni e generatori nei tuoi progetti JavaScript ed eleva le tue competenze di programmazione a nuovi livelli!

Argomenti Correlati

  • Iterabili — la base sincrona dietro for...of e Symbol.iterator.
  • Generatori — la sintassi function* su cui si basano i generatori asincroni.
  • Promise — ciò che ogni await all'interno di un generatore asincrono risolve.
  • Async/await — la sintassi con cui si abbina for await...of.

Pratica

Pratica
Cosa è vero riguardo agli iteratori e ai generatori asincroni di JavaScript?
Cosa è vero riguardo agli iteratori e ai generatori asincroni di JavaScript?
Was this page helpful?