W3docs

Fetch: abort

Aprenda a cancelar requisições fetch em JavaScript com AbortController e AbortSignal: cancelamentos por ação do usuário, timeouts, múltiplas requisições e tratamento correto de AbortError.

Uma vez que uma requisição fetch() está em andamento, ela continua executando até que o servidor responda — mesmo que o usuário tenha navegado para outra página, digitado um novo termo de busca ou a resposta não seja mais necessária. Essas requisições desperdiçadas ocupam conexões, consomem bateria e largura de banda, e podem entregar resultados desatualizados que sobrescrevem os mais recentes. A interface AbortController oferece uma maneira limpa e padronizada de cancelar uma requisição sob demanda.

Este capítulo mostra como configurar o AbortController, reagir a ações do usuário, criar timeouts, cancelar várias requisições ao mesmo tempo e tratar o AbortError resultante corretamente. Para saber mais sobre o fetch em si, consulte a página anterior, Fetch API.

Como o AbortController funciona

AbortController é um objeto pequeno com uma única finalidade: ele possui um AbortSignal e pode mudar esse sinal para o estado abortado. O sinal é a parte que você passa para o fetch() (e para muitas outras APIs do navegador, como addEventListener). Quando você chama controller.abort(), toda operação que recebeu esse sinal é cancelada.

O padrão sempre segue os mesmos três passos:

  1. Criar um controller: const controller = new AbortController().
  2. Passar controller.signal para o fetch() no objeto de opções.
  3. Chamar controller.abort() sempre que quiser cancelar.

Quando um fetch é abortado, sua promise rejeita com uma DOMException cujo name é "AbortError". É por isso que todos os exemplos abaixo verificam error.name === 'AbortError' — para que você possa ignorar o cancelamento intencional enquanto ainda expõe falhas reais de rede.

Uso básico do AbortController

Aqui está o menor exemplo completo. Ele aborta imediatamente para que você possa ver o caminho de rejeição:

javascript— editable

Criamos um AbortController, passamos seu signal para o fetch() e imediatamente chamamos controller.abort(). Como a requisição nunca é concluída normalmente, o .catch() é executado e reporta o cancelamento.

Inspecionando o sinal: aborted e o evento abort

O sinal expõe seu estado para que outro código possa reagir a um cancelamento. Dois membros são mais importantes:

  • signal.aborted — um boolean que se torna true após o cancelamento.
  • o evento "abort" — disparado no sinal no momento em que abort() é chamado.
javascript— editable

Isso é útil quando você tem trabalho que não envolve fetch (um timer, uma animação, um leitor de stream) que deve parar no momento em que a requisição é cancelada.

Um controller, um uso. Um controller não pode ser redefinido. Uma vez que você chame abort(), esse sinal permanece abortado para sempre, e qualquer novo fetch() iniciado com ele rejeita imediatamente. Para uma nova requisição, crie um novo AbortController.

Exemplo prático: abortando por ação do usuário

O motivo mais comum para abortar é o usuário mudar de ideia — clicar em "Cancelar", fechar um diálogo ou digitar uma nova consulta antes de a anterior terminar. Aqui, um botão cancela uma requisição em andamento:

<body>
  <button id="abortButton">Abort Fetch Request</button>
  <script>
    const controller = new AbortController();
    const signal = controller.signal;
    document.getElementById('abortButton').addEventListener('click', () => {
      controller.abort();
    });
    fetch('https://httpbin.org/delay/5', { signal })
      .then(response => response.json())
      .then(data => alert(
        'Data is successfully fetched! Refresh the page and try aborting.'
      ))
      .catch(error => {
        if (error.name === 'AbortError') {
          alert('Fetch request was aborted by the user');
        } else {
          alert('Fetch error: ' + error.message);
        }
      });
  </script>
</body>

Clicar no botão com o ID abortButton cancela a requisição fetch em andamento. O endpoint https://httpbin.org/delay/5 deliberadamente leva 5 segundos, portanto, se você clicar dentro desse intervalo, a requisição rejeita com AbortError.

Abortando várias requisições de uma vez

Um único sinal pode ser passado para várias requisições. Uma única chamada a controller.abort() cancela todas elas — útil quando uma página sai de uma view que iniciou vários carregamentos paralelos:

javascript— editable

Como as três requisições compartilham um único sinal, controller.abort() cancela todas em uma única chamada e o Promise.all rejeita com AbortError. Para saber mais sobre execução de requisições em paralelo, consulte Promise API.

Abortando após um timeout

Um uso muito comum do AbortController é dar um prazo a uma requisição: se o servidor for muito lento, cancelar e exibir um erro em vez de esperar indefinidamente.

A forma manual com setTimeout

Você pode combinar o controller com um timer e integrá-lo com qualquer outra lógica assíncrona. Aqui, uma operação separada dispara o abort após um segundo, enquanto o endpoint levaria cinco:

javascript— editable

O fetch é abortado pelo timer após um segundo, muito antes de o endpoint de cinco segundos poder responder. Leia mais sobre timers em async/await.

O atalho: AbortSignal.timeout()

Navegadores modernos (e Node 17.3+) incluem um helper integrado que cria um sinal que se aborta automaticamente após um número determinado de milissegundos — sem necessidade de controller ou setTimeout:

javascript— editable

Note que um abort por timeout rejeita com TimeoutError, e não com AbortError, então você pode distinguir "demorou demais" de "o usuário cancelou". Se você precisar de ambos — um timeout e um botão de cancelamento manual —, combine os sinais com AbortSignal.any([userSignal, AbortSignal.timeout(2000)]).

Tratando AbortError corretamente

Sempre que você aborta um fetch, a promise rejeita. Esquecer de tratar isso produz um ruidoso "uncaught promise rejection" no console, mesmo que o cancelamento tenha sido intencional. Duas regras mantêm as coisas organizadas:

  • Sempre inclua um .catch() (ou try/catch com await) em um fetch que pode ser abortado.
  • Dentro dele, verifique error.name e trate 'AbortError' / 'TimeoutError' como esperado — registre ou exiba apenas os outros erros. Consulte Tratamento de erros com promises para o padrão mais amplo.

Conclusão

AbortController é a forma padrão de cancelar requisições fetch() em JavaScript. Crie um controller, passe seu signal para uma ou mais requisições e chame abort() sempre que o trabalho não for mais necessário. Você viu cancelamento iniciado pelo usuário, timeouts manuais e integrados, cancelamento de várias requisições ao mesmo tempo e como tratar o AbortError resultante. Adotar esses padrões mantém suas aplicações responsivas e evita que desperdicem tempo com resultados que ninguém mais aguarda.

Prática

Prática
Qual é o propósito de passar a propriedade signal de um AbortController para uma requisição fetch?
Qual é o propósito de passar a propriedade signal de um AbortController para uma requisição fetch?
Was this page helpful?