Execução Sequencial de Promises com Array.prototype.reduce no JavaScript

Execução Sequencial de Promises com Array.prototype.reduce no JavaScript

Executar chamadas assíncronas concorrentemente com Promise.all pode sobrecarregar servidores ou ultrapassar limites de taxa (rate limits) de APIs externas. Encadeiar operações assíncronas usando o método Array.prototype.reduce() resolve esse problema, garantindo que cada Promise seja iniciada apenas após a conclusão bem-sucedida da anterior.

JavaScript

/**
 * Executa uma lista de tarefas assíncronas em sequência.
 * @param {Array<() => Promise<any>>} tarefas - Array de funções que retornam Promises.
 * @returns {Promise<Array<any>>} Promessa com o array de resultados em ordem.
 */
async function executarEmFila(tarefas) {
  // O acumulador inicia com uma Promise resolvida contendo um array vazio
  return tarefas.reduce(async (promessaAnterior, criarTarefa) => {
    const resultados = await promessaAnterior;
    const novoResultado = await criarTarefa();
    return [...resultados, novoResultado];
  }, Promise.resolve([]));
}

// --- Exemplo Prático de Uso ---
// Função simuladora de requisição assíncrona (ex: chamada de API)
const criarRequisicao = (id, ms) => () =>
  new Promise((resolve) => {
    setTimeout(() => {
      console.log(`[${new Date().toLocaleTimeString()}] Requisição ${id} concluída`);
      resolve(`Dados_${id}`);
    }, ms);
  });

// Fila de funções geradoras de Promises
const filaDeTarefas = [
  criarRequisicao(1, 1000), // Demora 1s
  criarRequisicao(2, 500),  // Demora 0.5s (aguarda a #1 finalizar)
  criarRequisicao(3, 800)   // Demora 0.8s (aguarda a #2 finalizar)
];

console.log('Iniciando processamento em fila...');
executarEmFila(filaDeTarefas).then((resultados) => {
  console.log('Todos os resultados recebidos:', resultados);
});

Pontos-chave

  • Funções Geradoras de Promises (Thunks): O array deve conter funções que retornam Promises, e não as Promises já instanciadas; caso contrário, as requisições dispararão em paralelo no momento da criação do array.
  • Início com Promise.resolve([]): Definir uma Promise resolvida contendo um array vazio como valor inicial do reduce estabelece o ponto de partida do encadeamento sem bloqueios.
  • Controle de Tratamento de Erros: Se uma Promise na fila for rejeitada, a execução sequencial será interrompida imediatamente, a menos que haja um bloco try/catch interno na função de callback da tarefa.
  • Alternativa Moderna com for...of: Para cenários mais simples sem acúmulo de estado no reduce, um loop for (const tarefa of tarefas) combinado com await oferece sintaxe equivalente com legibilidade direta.

Thales de Oliveira Gomes

Thales de Oliveira Gomes é gestor de Tecnologia da Informação, especialista em infraestrutura de redes, computação em nuvem e operações de TI hospitalar, com mais de 18 anos de experiência na área. Graduado em Gestão de TI e pós-graduado em Engenharia de Redes e Telecomunicações, Cloud Computing, Redes de Computadores e Gestão Hospitalar, construiu uma trajetória sólida liderando projetos de alta complexidade, como a implementação e migração para nuvem de sistemas ERP de grande porte. Sua atuação no setor o levou a ser indicado ao prêmio IT Leaders Brasil na categoria Rising Leaders. Além da carreira corporativa e da paixão por tecnologia, Thales é autor independente com mais de 70 obras publicadas sobre redes, segurança da informação, Linux e física, além de criador de conteúdo no blog Vetor Tech e na plataforma CiberDicas. No universo das artes e do entretenimento, atua como produtor de música eletrônica sob o projeto Yknex, cria ilustrações digitais e compartilha walkthroughs de games no YouTube.

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *