advanced async patterns

Módulo 2: JavaScript Assíncrono

Aula 2
1

Tratamento Avançado de Erros em Código Assíncrono

Aprenda padrões sofisticados de tratamento de erros para JavaScript assíncrono

Tratamento Avançado de Erros em Código Assíncrono

O tratamento adequado de erros é crucial para aplicações assíncronas robustas. Este guia cobre padrões avançados e melhores práticas.

Estratégias de Tratamento de Erros

1. Try-Catch com Async/Await

async function chamadaDeApiRobusta() {
  try {
    const resposta = await fetch('/api/dados');

    if (!resposta.ok) {
      throw new Error(`HTTP ${resposta.status}: ${resposta.statusText}`);
    }

    const dados = await resposta.json();
    return dados;
  } catch (erro) {
    if (erro instanceof TypeError) {
      // Erro de rede
      console.error('Erro de rede:', erro.message);
    } else if (erro.message.includes('HTTP')) {
      // Erro HTTP
      console.error('Erro de API:', erro.message);
    } else {
      // Erro desconhecido
      console.error('Erro inesperado:', erro);
    }
    throw erro; // Re-lança para o chamador tratar
  }
}

2. Padrões de Recuperação de Erros

Tentativa com Backoff Exponencial

async function tentarComBackoff(fn, maxTentativas = 3, atrasoBase = 1000) {
  for (let tentativa = 1; tentativa <= maxTentativas; tentativa++) {
    try {
      return await fn();
    } catch (erro) {
      if (tentativa === maxTentativas) {
        throw erro;
      }

      const atraso = atrasoBase * Math.pow(2, tentativa - 1);
      console.log(`Tentativa ${tentativa} falhou, tentando novamente em ${atraso}ms...`);
      await new Promise(resolve => setTimeout(resolve, atraso));
    }
  }
}

// Uso
const resultado = await tentarComBackoff(() => fetch('/api/endpoint-instavel'), 3, 1000);

Mecanismos de Fallback

async function buscarComFallback(urlPrimaria, urlFallback) {
  try {
    const resposta = await fetch(urlPrimaria);
    if (!resposta.ok) throw new Error('Serviço primário falhou');
    return await resposta.json();
  } catch (erroPrimario) {
    console.warn('Serviço primário falhou, tentando fallback:', erroPrimario.message);

    try {
      const resposta = await fetch(urlFallback);
      if (!resposta.ok) throw new Error('Serviço de fallback falhou');
      return await resposta.json();
    } catch (erroFallback) {
      throw new Error(`Ambos os serviços falharam: ${erroPrimario.message}, ${erroFallback.message}`);
    }
  }
}

3. Padrão Circuit Breaker

class CircuitBreaker {
  constructor(limite = 5, tempoDeEspera = 60000) {
    this.limite = limite;
    this.tempoDeEspera = tempoDeEspera;
    this.contadorDeFalhas = 0;
    this.estado = 'FECHADO'; // FECHADO, ABERTO, SEMIABERTO
    this.proximaTentativa = Date.now();
  }

  async chamar(fn) {
    if (this.estado === 'ABERTO') {
      if (Date.now() < this.proximaTentativa) {
        throw new Error('Circuit breaker está ABERTO');
      }
      this.estado = 'SEMIABERTO';
    }

    try {
      const resultado = await fn();
      this.aoSucesso();
      return resultado;
    } catch (erro) {
      this.aoFalhar();
      throw erro;
    }
  }

  aoSucesso() {
    this.contadorDeFalhas = 0;
    this.estado = 'FECHADO';
  }

  aoFalhar() {
    this.contadorDeFalhas++;
    if (this.contadorDeFalhas >= this.limite) {
      this.estado = 'ABERTO';
      this.proximaTentativa = Date.now() + this.tempoDeEspera;
    }
  }
}

// Uso
const breaker = new CircuitBreaker(3, 30000);

async function chamarServico() {
  return breaker.chamar(() => fetch('/api/servico'));
}

Agregação de Erros

Coletando Múltiplos Erros

async function processarItensComErros(itens) {
  const resultados = [];
  const erros = [];

  for (const item of itens) {
    try {
      const resultado = await processarItem(item);
      resultados.push(resultado);
    } catch (erro) {
      erros.push({ item, erro });
    }
  }

  if (erros.length > 0) {
    console.warn(`${erros.length} itens falharam ao processar:`, erros);
  }

  return { resultados, erros };
}

Tratamento de Sucesso Parcial

async function processamentoEmLote(itens, opcoes = {}) {
  const { falhaRapida = false, maxConcorrencia = 3 } = opcoes;
  const resultados = [];
  const erros = [];

  // Processar em lotes
  for (let i = 0; i < itens.length; i += maxConcorrencia) {
    const lote = itens.slice(i, i + maxConcorrencia);

    const promessasDoLote = lote.map(async (item, indice) => {
      try {
        const resultado = await processarItem(item);
        return { sucesso: true, resultado, item };
      } catch (erro) {
        if (falhaRapida) throw erro;
        return { sucesso: false, erro, item };
      }
    });

    const resultadosDoLote = await Promise.allSettled(promessasDoLote);

    resultadosDoLote.forEach(resultado => {
      if (resultado.status === 'fulfilled') {
        if (resultado.value.sucesso) {
          resultados.push(resultado.value.resultado);
        } else {
          erros.push(resultado.value);
        }
      } else {
        erros.push({ erro: resultado.reason });
      }
    });
  }

  return { resultados, erros, totalProcessado: itens.length };
}
2

Recursos de JavaScript Assíncrono

Recursos adicionais para dominar o JavaScript assíncrono

Reference

Recursos de JavaScript Assíncrono

Aqui estão alguns excelentes recursos para aprofundar sua compreensão do JavaScript assíncrono:

Documentação Oficial

Tópicos Avançados

  • Ferramentas de visualização do Event Loop
  • Profiling de performance para código assíncrono
  • Padrões avançados de promises
  • Geradores e iteradores assíncronos

Livros e Artigos

  • "Você Não Sabe JS: Async & Performance" por Kyle Simpson
  • "JavaScript Eficaz" por David Herman
  • "JavaScript: As Partes Boas" por Douglas Crockford

Ferramentas e Bibliotecas

  • Depuração assíncrona no Chrome DevTools
  • Biblioteca de promises Bluebird
  • RxJS para programação reativa
  • p-limit para controle de concorrência

Clique no link acima para explorar a documentação abrangente da MDN sobre promises em JavaScript!

2 content items