← Voltar na listagem

26 de setembro de 20246 min de leitura

Melhore o Desempenho com Chamadas de API Simultâneas usando Promise.all

Realize múltiplas chamadas de API de forma concorrente para otimizar o desempenho da sua aplicação!

Quando trabalhamos com aplicações que fazem várias requisições a APIs, é comum realizar essas chamadas de forma sequencial, o que pode impactar negativamente o desempenho. Neste artigo, vamos explorar como fazer múltiplas chamadas de API simultaneamente usando Promise.all, melhorando significativamente o tempo de resposta.

O Jeito Ruim: Chamadas Sequenciais

No exemplo abaixo, as chamadas de API são feitas uma após a outra, esperando a resposta de cada uma antes de prosseguir para a próxima:

async function fetchData() {
  const userResponse = await fetch('/api/user');
  const userData = await userResponse.json();

  const productsResponse = await fetch('/api/products');
  const productsData = await productsResponse.json();

  const ordersResponse = await fetch('/api/orders');
  const ordersData = await ordersResponse.json();

  // Utilize os dados aqui
}

Problema: Cada chamada de API aguarda a conclusão da anterior, aumentando o tempo total de execução proporcionalmente ao número de chamadas.

O Jeito Recomendado: Chamadas Concorrentes com Promise.all

Utilizando Promise.all, podemos iniciar todas as chamadas de API ao mesmo tempo e esperar que todas sejam concluídas:

async function fetchData() {
  const [userResponse, productsResponse, ordersResponse] = await Promise.all([
    fetch('/api/user'),
    fetch('/api/products'),
    fetch('/api/orders')
  ]);

  const [userData, productsData, ordersData] = await Promise.all([
    userResponse.json(),
    productsResponse.json(),
    ordersResponse.json()
  ]);

  // Utilize os dados aqui
}

Vantagem: As chamadas de API são iniciadas simultaneamente, reduzindo significativamente o tempo total de espera.

Explicação Detalhada

Chamadas Sequenciais vs. Concorrentes

  • Sequenciais: A próxima chamada só é iniciada após a conclusão da anterior.
  • Concorrentes: Todas as chamadas são iniciadas quase ao mesmo tempo, sem esperar pelas anteriores.

Por Que Promise.all é Eficiente?

  • Execução Simultânea: Inicia todas as promessas ao mesmo tempo.
  • Sincronização: Aguarda que todas sejam resolvidas ou que uma seja rejeitada.
  • Melhor Desempenho: Reduz o tempo total de espera ao máximo tempo individual de uma chamada, em vez da soma dos tempos.

Outro Método: Iniciando Chamadas Sem Promise.all

Também podemos iniciar as chamadas sem esperar, armazenando as promessas e aguardando sua resolução posteriormente:

async function fetchData() {
  const userPromise = fetch('/api/user');
  const productsPromise = fetch('/api/products');
  const ordersPromise = fetch('/api/orders');

  const userResponse = await userPromise;
  const productsResponse = await productsPromise;
  const ordersResponse = await ordersPromise;

  const userData = await userResponse.json();
  const productsData = await productsResponse.json();
  const ordersData = await ordersResponse.json();

  // Utilize os dados aqui
}

Observação: Embora funcione, o uso de Promise.all torna o código mais limpo e fácil de entender.

Lidando com Erros: Promise.all vs. Promise.allSettled

Comportamento do Promise.all

Se alguma das promessas for rejeitada, o Promise.all rejeita imediatamente com o erro da promessa que falhou:

async function fetchData() {
  try {
    const responses = await Promise.all([
      fetch('/api/user'),
      fetch('/api/products'),
      fetch('/api/orders')
    ]);

    // Processamento dos dados...

  } catch (error) {
    console.error('Uma das chamadas de API falhou:', error);
  }
}

Quando usar: Quando a falha de uma chamada invalida todo o conjunto de dados que você precisa.

Usando Promise.allSettled para Mais Resiliência

Se você precisa que todas as chamadas sejam concluídas, mesmo que algumas falhem, use Promise.allSettled:

async function fetchData() {
  const results = await Promise.allSettled([
    fetch('/api/user'),
    fetch('/api/products'),
    fetch('/api/orders')
  ]);

  results.forEach((result) => {
    if (result.status === 'fulfilled') {
      // result.value contém a resposta bem-sucedida
    } else {
      // result.reason contém o erro
      console.error('Erro na chamada de API:', result.reason);
    }
  });

  // Utilize os dados disponíveis
}

Vantagens:

  • Robustez: Continua executando mesmo se algumas promessas forem rejeitadas.
  • Feedback Completo: Fornece o status de cada promessa, permitindo tratamento individual.

Comparação de Abordagens

Método Quando Usar
Chamadas Sequenciais Quando as chamadas dependem umas das outras.
Promise.all Quando todas as chamadas são independentes e a falha de uma invalida o resultado.
Promise.allSettled Quando deseja obter o máximo de dados possível, mesmo se algumas chamadas falharem.

Exemplo Prático Completo

Código Sequencial (Ineficiente)

async function getData() {
  const user = await fetchUser();
  const profile = await fetchUserProfile(user.id);
  const posts = await fetchUserPosts(user.id);

  return { user, profile, posts };
}

Código Concorrente com Promise.all (Eficiente)

async function getData() {
  const userPromise = fetchUser();

  const [user, profile, posts] = await Promise.all([
    userPromise,
    userPromise.then(user => fetchUserProfile(user.id)),
    userPromise.then(user => fetchUserPosts(user.id))
  ]);

  return { user, profile, posts };
}

Nota: Neste exemplo, usamos o resultado de userPromise para iniciar as outras chamadas, mantendo a execução concorrente onde possível.

Conclusão

Utilizar chamadas de API simultâneas pode melhorar significativamente o desempenho da sua aplicação. Ao optar por Promise.all ou Promise.allSettled, você tem controle sobre como lidar com possíveis falhas e pode otimizar a experiência do usuário.

Dicas Finais:

  • Analise as Dependências: Certifique-se de que as chamadas não dependem umas das outras antes de executá-las simultaneamente.
  • Gerencie Erros Adequadamente: Escolha entre Promise.all e Promise.allSettled com base em como você deseja lidar com erros.
  • Mantenha o Código Legível: Prefira abordagens que tornem o código mais claro e fácil de manter.

Referências:


Esperamos que este artigo ajude você a melhorar o desempenho das suas aplicações JavaScript ao lidar com múltiplas chamadas de API!