← JavaScript: linguagem e diagnóstico de aplicações
08 / 10 · 55 MIN

Eventos, HTTP e cancelamento no navegador

Liga eventos e respostas HTTP a contratos de dados e de interface; controla resultados antigos e interpreta o alcance do cancelamento.

Linguagem e serviços do navegador

Promises, funções e objetos pertencem à linguagem; DOM, eventos, fetch e AbortController são serviços do ambiente de navegador usados nesta aula. Uma função JavaScript válida pode depender de APIs que outro ambiente não fornece. Declara o contexto antes de interpretar um exemplo e não concluas compatibilidade de todos os navegadores apenas porque uma edição de ECMAScript está publicada.

Um pedido HTTP tem várias fronteiras observáveis. Fetch produz uma Response quando recebe a resposta inicial acessível; isso não significa que o corpo já foi totalmente lido nem que os dados são válidos para a aplicação. Uma rejeição de rede, um estado HTTP de erro, JSON malformado e um campo obrigatório ausente são resultados diferentes. Mantém essas distinções no diagnóstico, mesmo que a interface apresente uma mensagem curta comum.

Identidade do listener e do evento

Num botão com um ícone descendente, um click no ícone pode ter esse descendente como target, enquanto currentTarget identifica o botão cujo listener está a executar. Esta distinção evita aplicar uma ação ao elemento errado. currentTarget só tem o significado do listener durante a sua execução; se precisas da referência mais tarde, guarda o elemento numa variável enquanto o handler está ativo. Conservar o objeto event não fixa todas as suas propriedades transitórias.

Para remover um listener, conserva a identidade da função e usa o mesmo tipo de evento e valor de capture. Uma nova arrow com o mesmo corpo continua a ser outra função. Um listener registado com capture true não é removido pela variante false. A remoção não exige que todas as outras opções, como passive, sejam repetidas; não confundas a configuração inicial com os critérios de correspondência usados na remoção.

Ação por omissão e apresentação textual

preventDefault trata a ação por omissão de um evento cancelável, desde que o listener não seja passivo. Não remove o listener e não para, por si só, a propagação para outros listeners. Um problema de navegação ou submissão não se resolve automaticamente com uma regra de propagação, e um problema de listeners duplicados não se resolve cancelando a ação por omissão. Identifica primeiro que efeito está a ocorrer.

Para mostrar um rótulo externo como texto literal, textContent evita interpretar a string como marcação HTML. Atribuir "<b>Ready</b>" deve mostrar esses caracteres quando esse é o contrato. Esta atribuição substitui os filhos anteriores do elemento, pelo que o destino deve ser escolhido com cuidado. Não é um mecanismo universal para validar URLs, regras de negócio ou outros contextos de saída; cumpre a tarefa delimitada de apresentar texto.

Estado HTTP, corpo e contrato de dados

Uma resposta 404 normal não rejeita automaticamente a promise de fetch. Verifica response.ok ou o estado específico que o contrato permite. response.ok cobre os estados de sucesso 200–299; não demonstra que o corpo tem os campos necessários. response.json() é outra operação assíncrona: pode falhar na leitura ou na sintaxe e, quando tem sucesso, ainda pode produzir null, um array ou outro valor que a aplicação não aceita.

O corpo é um fluxo consumível. Depois de uma leitura bem-sucedida de um corpo JSON não nulo, chamar json() novamente no mesmo Response não fornece uma cache do objeto. Retém o valor já interpretado ou, se precisas de consumidores independentes, prepara um clone antes de consumir. Também não uses no-cors como solução para ler uma resposta bloqueada: uma resposta opaca não disponibiliza ao script o corpo e os cabeçalhos que este exemplo exige.

Cancelar e decidir se um resultado ainda é corrente

AbortController permite pedir cancelamento a operações que recebem o seu signal. Esse pedido pode fazer falhar fetch ou a leitura do corpo, mesmo depois de a Response inicial ter chegado. Sem motivo personalizado, o caso normal de cancelamento usa AbortError. A observação é local: não prova que o servidor nunca começou o trabalho nem que desfez uma escrita já aceite. Se o resultado de uma criação é desconhecido, usa o contrato de identidade e consulta do serviço antes de decidir repetir.

Numa pesquisa, cancelar a consulta antiga pode reduzir trabalho inútil, mas a publicação também precisa de uma guarda de identidade. Dá a cada consulta uma geração crescente e compara-a com a corrente imediatamente antes de alterar a interface. A resposta que chega por último pode ser antiga. Aplica a mesma guarda ao caminho de erro: uma falha antiga também não deve substituir resultados atuais por uma mensagem de indisponibilidade.

Exemplo orientado: um rótulo corrente

createLabelLoader cria estado privado para um elemento. Cada load incrementa generation, pede cancelamento ao pedido anterior e guarda um novo controller. mine retém a geração desta chamada. As verificações HTTP e de esquema antecedem a publicação do rótulo. O contrato aceita uma string com até 200 unidades UTF-16, incluindo a string vazia; não está a contar caracteres visuais. textContent apresenta o rótulo literalmente.

Segue A com mine 1 e B com mine 2. Se B já começou, A não pode publicar nem no sucesso nem no catch, porque a geração corrente é 2. O finally de A também não pode limpar active: essa referência já pode pertencer a B. A guarda no finally preserva a capacidade de uma chamada seguinte cancelar B. Não há await entre a última comparação de geração e a atribuição de texto, no contexto DOM comum indicado.

Limites do exemplo e diagnóstico útil

O exemplo é um adaptador de apresentação para GETs autorizados, não uma função genérica que devolve dados de negócio. O seu catch converte uma falha corrente em "Unavailable"; a promise de load não certifica sucesso de obtenção de dados. Numa aplicação que precisa de classificar falhas, preserva estado explícito ou diagnóstico interno adequado. O rótulo curto, por si só, não distingue rede, HTTP, JSON e esquema.

Antes de alterar o código, reconstrói a sequência: consulta escolhida, geração, pedido iniciado, cabeçalhos, corpo, validação e decisão de publicação. Não introduzas atrasos fixos para esconder uma corrida. Se o problema envolve escrita remota, o exemplo de rótulo não fornece idempotência nem rollback; usa o contrato específico do serviço. As perguntas avaliam estas decisões através de excertos e cenários, sem exigir execução no navegador.

function createLabelLoader(label) {
  let generation = 0;
  let active = null;
  return async function load(url) {
    const mine = ++generation;
    if (active !== null) active.abort();
    const controller = new AbortController();
    active = controller;
    label.textContent = "Loading";
    try {
      const response = await fetch(url, { signal: controller.signal });
      if (!response.ok) throw new Error("HTTP " + response.status);
      const data = await response.json();
      if (data === null || typeof data !== "object" || Array.isArray(data) ||
          typeof data.label !== "string" || data.label.length > 200) {
        throw new TypeError("label schema");
      }
      if (mine !== generation) return;
      label.textContent = data.label;
    } catch (error) {
      if (mine !== generation) return;
      label.textContent = "Unavailable";
    } finally {
      if (mine === generation) active = null;
    }
  };
}
NA PRÁTICA

O elemento label é um elemento DOM comum já existente e destinado apenas a texto. Os URLs são GETs de leitura autorizados da aplicação. O código usa APIs padrão de navegador.

Considera duas chamadas consecutivas, A e B, cujas respostas podem terminar fora de ordem; acompanha mine, generation e active.

Armadilhas comuns

Remover listeners com outra função; assumir que preventDefault para propagação; ler o corpo duas vezes; usar innerHTML para texto externo; tratar abort como confirmação de ausência de efeitos.

Tópicos relacionados: Erros, validação e contratos de falha · JSON, texto e contratos de tempo · Promises, async e propagação de erros · Estado, ordem e diagnóstico de integração

Leva esta ideia contigo

Cada fronteira tem um resultado próprio. Valida a resposta e a sua identidade antes de publicar; o cancelamento local não descreve sozinho o estado remoto.

Criar conta

Referência: Using Fetch · ECMAScript 2026 (17th edition); browser APIs identified separately