Usamos cookies para medir audiência e melhorar sua experiência. Você pode aceitar ou recusar a qualquer momento. Veja sobre o iMasters.
Quando falamos de manipulação assíncrona em JavaScript, um erro comum é tentar usar async/await dentro de loops do tipo forEach. Muitos desenvolvedores acreditam que essa combinação é eficiente e segura, mas na prática, ela costuma gerar comportamentos inesperados ou erros de lógica.
---
A função forEach executa suas callbacks de forma assíncrona, mas sem esperar que elas terminem. Assim, mesmo usando async/await dentro de um forEach, o loop não aguarda a finalização de cada operação assíncrona. O resultado é que as tarefas são disparadas quase simultaneamente, e a função principal termina antes que todas sejam concluídas.
Esse comportamento pode parecer desejável em alguns casos, como processamento paralelo, mas na maioria das vezes causa dificuldades na garantia de ordem ou controle de fluxo.
---
Ao usar um código como:
files.forEach(async (file) => {
const contents = await fs.readFile(file, 'utf8'). console.log(contents). }).
O que acontece é que o método forEach ignora as promessas retornadas pela callback async. Assim, o processamento de leitura de arquivos ocorre em paralelo, mas a função que chamou o forEach não aguarda sua conclusão. Isso pode levar a problemas de sincronização, especialmente se o fluxo depende de todos os arquivos serem lidos antes de continuar. Por isso, o recorte precisa considerar manutenção, validação e caminho de volta.
#### Leitura sequencial
Para garantir a leitura na ordem, o ideal é usar um loop for…of, que suporta await de forma nativa: Esse contexto ajuda a separar ganho real de novidade difícil de sustentar. A decisão fica mais saudável quando o time consegue medir o impacto depois. Sem esse critério, a solução pode parecer simples no começo e cara no suporte. O valor aparece melhor quando operação, produto e engenharia olham para o mesmo risco. Por isso, o recorte precisa considerar manutenção, validação e caminho de volta.
async function printFiles() {
const files = await getFilePaths(). for (const file of files) {
const contents = await fs.readFile(file, 'utf8'). console.log(contents). }
} A decisão fica mais saudável quando o time consegue medir o impacto depois.
Assim, cada arquivo só será lido após o anterior, garantindo controle total da sequência. Sem esse critério, a solução pode parecer simples no começo e cara no suporte. O valor aparece melhor quando operação, produto e engenharia olham para o mesmo risco. Por isso, o recorte precisa considerar manutenção, validação e caminho de volta. Esse contexto ajuda a separar ganho real de novidade difícil de sustentar. A decisão fica mais saudável quando o time consegue medir o impacto depois. Sem esse critério, a solução pode parecer simples no começo e cara no suporte. O valor aparece melhor quando operação, produto e engenharia olham para o mesmo risco.
#### Leitura paralela
Se o objetivo for otimizar o tempo e ler todos os arquivos simultaneamente, a estratégia é usar map para criar um array de promessas e Promise.all para aguardar todas ao mesmo tempo: O valor aparece melhor quando operação, produto e engenharia olham para o mesmo risco. Por isso, o recorte precisa considerar manutenção, validação e caminho de volta. Esse contexto ajuda a separar ganho real de novidade difícil de sustentar. A decisão fica mais saudável quando o time consegue medir o impacto depois. Sem esse critério, a solução pode parecer simples no começo e cara no suporte. O valor aparece melhor quando operação, produto e engenharia olham para o mesmo risco. Por isso, o recorte precisa considerar manutenção, validação e caminho de volta.
async function printFiles() {
const files = await getFilePaths(). await Promise.all(
files.map(async (file) => {
const contents = await fs.readFile(file, 'utf8'). console.log(contents). })
). } Por isso, o recorte precisa considerar manutenção, validação e caminho de volta. O valor aparece melhor quando operação, produto e engenharia olham para o mesmo risco. O valor aparece melhor quando operação, produto e engenharia olham para o mesmo risco. O valor aparece melhor quando operação, produto e engenharia olham para o mesmo risco. O valor aparece melhor quando operação, produto e engenharia olham para o mesmo risco. O valor aparece melhor quando operação, produto e engenharia olham para o mesmo risco. O valor aparece melhor quando operação, produto e engenharia olham para o mesmo risco. O valor aparece melhor quando operação, produto e engenharia olham para o mesmo risco.
Aqui, todas as leituras acontecem em paralelo e o código aguarda até que todas sejam concluídas. Esse contexto ajuda a separar ganho real de novidade difícil de sustentar. Por isso, o recorte precisa considerar manutenção, validação e caminho de volta. Por isso, o recorte precisa considerar manutenção, validação e caminho de volta. Por isso, o recorte precisa considerar manutenção, validação e caminho de volta. Por isso, o recorte precisa considerar manutenção, validação e caminho de volta. Por isso, o recorte precisa considerar manutenção, validação e caminho de volta. Esse contexto ajuda a separar ganho real de novidade difícil de sustentar. Por isso, o recorte precisa considerar manutenção, validação e caminho de volta.
---
O uso de leitura sequencial garante controle de ordem, mas pode impactar o desempenho em operações de I/O que suportam paralelismo. Já a abordagem paralela melhora o tempo total, porém, pode sobrecarregar o sistema ou a rede se muitas operações forem disparadas simultaneamente. A decisão fica mais saudável quando o time consegue medir o impacto depois. Esse contexto ajuda a separar ganho real de novidade difícil de sustentar. Esse contexto ajuda a separar ganho real de novidade difícil de sustentar. Esse contexto ajuda a separar ganho real de novidade difícil de sustentar. Esse contexto ajuda a separar ganho real de novidade difícil de sustentar. A decisão fica mais saudável quando o time consegue medir o impacto depois.
Além disso, é importante lembrar que, em qualquer cenário, a gestão de erros deve ser considerada. Usar try/catch ao redor de cada leitura ou envolver Promise.all com tratamento de rejeições é fundamental para evitar que uma falha interrompa o processo completo. Sem esse critério, a solução pode parecer simples no começo e cara no suporte. A decisão fica mais saudável quando o time consegue medir o impacto depois. A decisão fica mais saudável quando o time consegue medir o impacto depois. A decisão fica mais saudável quando o time consegue medir o impacto depois. Sem esse critério, a solução pode parecer simples no começo e cara no suporte. A decisão fica mais saudável quando o time consegue medir o impacto depois.
Nunca confie cegamente na compatibilidade do async/await com estruturas como forEach. Para operações sequenciais, prefira for…of. para paralelas, use map e Promise.all. Assim, você evita bugs difíceis de detectar e garante que seu código seja previsível e confiável. O valor aparece melhor quando operação, produto e engenharia olham para o mesmo risco. Sem esse critério, a solução pode parecer simples no começo e cara no suporte. Sem esse critério, a solução pode parecer simples no começo e cara no suporte. Sem esse critério, a solução pode parecer simples no começo e cara no suporte. Sem esse critério, a solução pode parecer simples no começo e cara no suporte. O valor aparece melhor quando operação, produto e engenharia olham para o mesmo risco.
E o que vocês acham? Já passaram por situações em que esse tipo de problema causou dor de cabeça na produção? Compartilhem suas experiências. Por isso, o recorte precisa considerar manutenção, validação e caminho de volta. O valor aparece melhor quando operação, produto e engenharia olham para o mesmo risco. O valor aparece melhor quando operação, produto e engenharia olham para o mesmo risco. O valor aparece melhor quando operação, produto e engenharia olham para o mesmo risco. O valor aparece melhor quando operação, produto e engenharia olham para o mesmo risco. Por isso, o recorte precisa considerar manutenção, validação e caminho de volta. O valor aparece melhor quando operação, produto e engenharia olham para o mesmo risco.
pra mim o maior erro é usar forEach achando que vai fazer tudo na ordem.
cara, acho que a maior pegadinha é justamente não perceber que o forEach não espera as promises. já passei por isso e é um susto quando o código parece funcionar, mas na hora de depurar, nada faz sentido.
exatamente. eu faria assim: se precisa de ordem, for…of. se não, promise.all. difícil é lembrar na hora de escrever o código, depois fica mais fácil de manter.