Como executar código assíncrono em paralelo?
Em JavaScript, uma das grandes vantagens do uso de Promises é a capacidade de realizar múltiplas tarefas assíncronas ao mesmo tempo. Em vez de esperar que uma tarefa seja concluída antes de iniciar a próxima, você pode executar várias operações de forma simultânea, o que pode melhorar significativamente o desempenho e a experiência do usuário. Neste tutorial, vamos aprender a executar código assíncrono em paralelo usando técnicas como Promise.all()
e Promise.race()
.
Usando Promise.all()
para executar tarefas em paralelo
O Promise.all()
é uma função poderosa que permite executar várias Promises em paralelo. Ele recebe um array de Promises e retorna uma única Promise que resolve quando todas as Promises do array forem resolvidas. Isso permite que você execute várias operações assíncronas ao mesmo tempo e aguarde a conclusão de todas elas antes de continuar.
Exemplo básico de como usar Promise.all()
:
let promise1 = fetch('https://api.exemplo1.com');
let promise2 = fetch('https://api.exemplo2.com');
Promise.all([promise1, promise2])
.then(responses => {
return Promise.all(responses.map(response => response.json()));
})
.then(data => console.log(data))
.catch(error => console.log('Erro:', error));
Neste exemplo, estamos fazendo duas requisições fetch
em paralelo. Promise.all()
aguarda que ambas as Promises sejam resolvidas e, em seguida, converte as respostas para JSON. Caso alguma Promise falhe, a Promise retornada por Promise.all()
será rejeitada e o erro será capturado pelo catch()
.
Usando Promise.race()
para obter o primeiro resultado
O Promise.race()
é semelhante ao Promise.all()
, mas com uma diferença crucial: ele resolve ou rejeita assim que a primeira Promise do array for resolvida ou rejeitada. Isso é útil quando você precisa esperar pela primeira resposta de várias fontes ou quando você precisa de uma tarefa mais rápida.
Exemplo de como usar Promise.race()
:
let promise1 = new Promise((resolve, reject) => setTimeout(resolve, 100, 'Primeiro')); // Resolve após 100ms
let promise2 = new Promise((resolve, reject) => setTimeout(resolve, 200, 'Segundo')); // Resolve após 200ms
Promise.race([promise1, promise2])
.then(result => console.log(result))
.catch(error => console.log('Erro:', error));
Aqui, Promise.race()
vai resolver com o valor da primeira Promise que for resolvida, neste caso, a promise1
, que resolve após 100ms.
Execução de código assíncrono paralelo com async/await
Quando você usa async/await
, pode ser mais fácil escrever código assíncrono de maneira sequencial, mas também é possível executar código assíncrono em paralelo. Para isso, você pode criar múltiplas Promises e aguardá-las todas ao mesmo tempo com await
em conjunto com Promise.all()
.
Exemplo de como executar código assíncrono em paralelo com async/await
:
async function buscarDados() {
try {
let [dados1, dados2] = await Promise.all([
fetch('https://api.exemplo1.com').then(res => res.json()),
fetch('https://api.exemplo2.com').then(res => res.json())
]);
console.log(dados1, dados2);
} catch (error) {
console.log('Erro:', error);
}
}
buscarDados();
Aqui, estamos fazendo duas requisições fetch
em paralelo e aguardando ambas serem resolvidas ao mesmo tempo usando await
dentro de Promise.all()
. Assim que ambas as Promises são resolvidas, os resultados são logados no console.
Por que usar tarefas assíncronas em paralelo?
Executar tarefas em paralelo pode ser muito vantajoso, especialmente quando você precisa fazer múltiplas operações assíncronas independentes. Isso melhora o desempenho geral da aplicação, pois não há bloqueio esperando cada tarefa ser concluída uma de cada vez. Além disso, é muito útil para melhorar a experiência do usuário, especialmente em aplicações web interativas e dinâmicas.
Alguns cenários em que você pode usar a execução paralela incluem:
- Carregar dados de múltiplas APIs ao mesmo tempo.
- Executar várias operações de IO (input/output) sem bloquear a execução do código principal.
- Realizar múltiplas tarefas que não dependem umas das outras e podem ser feitas simultaneamente.
Considerações importantes ao usar código paralelo
Embora a execução em paralelo seja útil, é importante considerar o controle de erros. Como você pode estar lidando com múltiplas Promises, é necessário capturar erros adequadamente para garantir que sua aplicação não quebre inesperadamente.
Quando usar Promise.all()
, se qualquer uma das Promises falhar, o erro será imediatamente propagado, e todas as outras Promises serão ignoradas. Já com Promise.race()
, o primeiro erro ou resultado é imediatamente tratado.
Conclusão
O uso de tarefas assíncronas em paralelo é uma estratégia poderosa para melhorar a performance e a eficiência das suas aplicações JavaScript. Técnicas como Promise.all()
e Promise.race()
permitem executar múltiplas tarefas ao mesmo tempo, sem bloqueios, e ajudam a acelerar o tempo de resposta e a interatividade em aplicativos modernos. Ao entender e utilizar essas funções de forma eficaz, você pode melhorar significativamente a experiência do usuário e a performance do seu código.
Por que executar código assíncrono em paralelo melhora a performance
Quando estamos lidando com múltiplas operações assíncronas, como requisições de rede ou manipulação de dados, a execução em paralelo torna-se crucial. Usar Promise.all()
ou Promise.race()
permite que várias tarefas sejam feitas ao mesmo tempo, sem que uma precise esperar pela outra, resultando em um código mais eficiente e rápido. Isso é especialmente importante em situações onde a latência é crítica, como em aplicativos de tempo real.
Algumas aplicações:
- Realizar múltiplas requisições a APIs ao mesmo tempo para acelerar o tempo de carregamento.
- Executar tarefas paralelas em operações de leitura e escrita de arquivos em sistemas back-end.
- Trabalhar com animações simultâneas e interações de usuário, sem travar o thread principal.
- Otimizar o desempenho de jogos e aplicativos interativos, realizando múltiplas operações em paralelo sem bloquear a interface do usuário.
Dicas para quem está começando
- Quando começar a trabalhar com paralelismo, experimente com exemplos simples de
Promise.all()
para entender como ela executa várias tarefas simultaneamente. - Certifique-se de que as tarefas sejam independentes para garantir que elas possam ser executadas em paralelo sem depender umas das outras.
- Use
Promise.race()
quando precisar obter o resultado da primeira tarefa que for completada, seja ela bem-sucedida ou não. - Se for realizar várias requisições a APIs, use
Promise.all()
para otimizar o tempo de carregamento das informações.
Contribuições de Ricardo Vasconcellos