forEach/map e async não andam de mãos dadas
Às vezes, tendemos a passar funções assíncronas com funções forEach e map.
Por exemplo:
[1,2,3,4,5].forEach(async (n) => setTimeout(console.log(n), 1000));
Resultado: Todos os números de 1 a 5 são impressos um após o outro, mas não há intervalo de 1 segundo após a impressão de cada linha.
Por que isso acontece?
Olhe para esta função javascipt:
async function doubleOf(n) {
return n*2;
}
Resultado: na verdade, está retornando uma promessa que resolve um número.
Se escrevermos um Typescript equivalente a esta função com tipos estritos, isso tornará as coisas mais claras.
O seguinte código não compila:
async function doubleOf(n: number): number {
return n*2;
}
A versão correta seria:
async function doubleOf(n: number): Promise<number> {
return n*2;
}
Não se deixe enganar pelo açúcar sintático fornecido pelo async-await. Se escrevêssemos promessas puras sem usar async, a função acima ficaria assim:
function doubleOf(n) {
return new Promise((resolve) => resolve(n*2));
}
function doubleOf(n: number): Promise<number> {
return new Promise((resolve) => resolve(n*2));
}
- Temos
doubleOfuma função que recebe um número e retorna um número. Javascript simples e antigo. - Temos
doubleOfOldWayuma função que recebe um número e retorna uma promessa que resolve um número. - Temos
doubleOfNewWay, uma função assíncrona que recebe um número e parece que retorna um número, mas na verdade retorna uma promessa que resolve para um número exatamente como adoubleOfOldWayfunção. doubleOfOldWayedoubleOfNewWayas funções são exatamente as mesmas.- E, portanto, quando tentamos executar uma operação de multiplicação em valores retornados por
doubleOfOldWayedoubleOfNewWayfunções, o resultado foiNaN, pois não podemos múltiplas promessas (obviamente!). - Para multiplicar
doubleOfOldWayedoubleOfNewWay:
Então, voltando ao nosso exemplo inicial:
[1,2,3,4,5].forEach(async (n) => setTimeout(console.log(n), 1000));
A maneira mais correta de implementar o que esperamos dessa função forEach é usando um loop for simples:
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}
Para obter uma lista do dobro de cada número, o que podemos fazer é:
await Promise.all([1,2,3,4,5].map(async (n) => n*2));
[2, 4, 6, 8, 10]




































![O que é uma lista vinculada, afinal? [Parte 1]](https://post.nghiatu.com/assets/images/m/max/724/1*Xokk6XOjWyIGCBujkJsCzQ.jpeg)