forEach/map e async non vanno di pari passo
A volte, tendiamo spesso a passare funzioni asincrone con funzioni forEach e map.
Per es:
[1,2,3,4,5].forEach(async (n) => setTimeout(console.log(n), 1000));
Risultato: tutti i numeri da 1 a 5 vengono stampati uno dopo l'altro ma non c'è intervallo di 1 secondo dopo la stampa di ciascuna riga.
Perché succede?
Guarda questa funzione javascript:
async function doubleOf(n) {
return n*2;
}
Risultato: questo in realtà restituisce una Promessa che si risolve in un numero.
Se scriviamo un equivalente Typescript di questa funzione con tipi rigorosi, chiarirà le cose.
Il seguente codice non verrà compilato:
async function doubleOf(n: number): number {
return n*2;
}
La versione corretta sarebbe:
async function doubleOf(n: number): Promise<number> {
return n*2;
}
Non lasciarti ingannare dallo zucchero sintattico fornito da async-await. Se scrivessimo promesse pure senza usare async, la funzione sopra sarebbe simile a:
function doubleOf(n) {
return new Promise((resolve) => resolve(n*2));
}
function doubleOf(n: number): Promise<number> {
return new Promise((resolve) => resolve(n*2));
}
- Abbiamo
doubleOfuna funzione che accetta un numero e restituisce un numero. Semplice vecchio javascript. - Abbiamo
doubleOfOldWayuna funzione che accetta un numero e restituisce una promessa che si risolve in un numero. - Abbiamo
doubleOfNewWay, una funzione asincrona che accetta un numero e sembra che restituisca un numero, ma in realtà restituisce una promessa che si risolve in un numero proprio come ladoubleOfOldWayfunzione. doubleOfOldWayedoubleOfNewWayle funzioni sono esattamente le stesse.- E quindi, quando proviamo ad eseguire un'operazione di moltiplicazione sui valori restituiti da
doubleOfOldWayedoubleOfNewWayfunzioni, il risultato è statoNaN, poiché non possiamo più promesse (ovviamente!). - Moltiplicare
doubleOfOldWayedoubleOfNewWay:
Quindi torniamo al nostro esempio iniziale:
[1,2,3,4,5].forEach(async (n) => setTimeout(console.log(n), 1000));
Il modo più corretto per implementare ciò che ci aspettiamo da questa funzione forEach è usare un semplice ciclo for:
for(const number of [1,2,3,4,5]) {
console.log(number);
await new Promise(resolve => setTimeout(resolve, 1000)); // Sleep for "atleast" 1 second
}
[1,2,3,4,5].map(async (n) => n*2);
(5) [Promise, Promise, Promise, Promise, Promise]
0: Promise {<fulfilled>: 2}
1: Promise {<fulfilled>: 4}
2: Promise {<fulfilled>: 6}
3: Promise {<fulfilled>: 8}
4: Promise {<fulfilled>: 10}
Per ottenere un elenco di doppio di ogni numero, quello che possiamo fare è:
await Promise.all([1,2,3,4,5].map(async (n) => n*2));
[2, 4, 6, 8, 10]
![Che cos'è un elenco collegato, comunque? [Parte 1]](https://post.nghiatu.com/assets/images/m/max/724/1*Xokk6XOjWyIGCBujkJsCzQ.jpeg)



































