12k
All articles

5 APIs JavaScript que Todo Desenvolvedor Frontend Deve Conhecer

5 APIs nativas de JavaScript para frontend: IntersectionObserver, ResizeObserver, AbortController, Clipboard API e View Transitions.

OpenReplay Team
OpenReplay Team
5 APIs JavaScript que Todo Desenvolvedor Frontend Deve Conhecer

As cinco APIs nativas do browser mais importantes para aprender agora são IntersectionObserver, ResizeObserver, AbortController, a Clipboard API e a View Transitions API: cada uma substitui uma dependência comum por uma primitiva da plataforma disponível em todos os browsers modernos.

A maioria de nós aprende isso da forma mais difícil — importando uma biblioteca inteira para um botão de copiar, ou perdendo uma tarde inteira com uma caixa de busca que continua exibindo resultados desatualizados — apenas para descobrir depois que o browser já tinha a solução. Se você já utiliza fetch, localStorage e o DOM, mas ainda não explorou as APIs de observer e utilitários mais recentes, esta é a lista essencial que permite eliminar uma ou duas dependências do seu projeto. Tudo o que está abaixo é uma API nativa da plataforma web, não um serviço REST hospedado como TMDB ou Unsplash, portanto não há chave de API, nenhum servidor e nenhum custo de execução além do browser que você já utiliza como alvo. Cada item inclui uma definição em uma linha, um trecho de código funcional e mínimo, um caso de uso real e uma nota honesta sobre suporte.

Principais Conclusões

  • IntersectionObserver reporta quando um elemento entra ou sai da viewport sem a necessidade de um listener de scroll, e está disponível como Baseline em todos os browsers desde março de 2019.
  • ResizeObserver reage às mudanças de tamanho do próprio content-box ou border-box de um elemento, o que torna possível a criação de componentes responsivos ao contêiner — algo que o evento resize da window não consegue fazer.
  • AbortController é a solução padrão para race conditions no React: passe controller.signal para o fetch e chame controller.abort() no cleanup do effect para que uma resposta desatualizada não sobrescreva a UI atual.
  • navigator.clipboard.writeText() é o substituto baseado em Promises para o hack com document.execCommand('copy'), mas só funciona em um contexto seguro (HTTPS ou localhost).
  • As View Transitions para o mesmo documento atingiram o status de Baseline Newly available em 14 de outubro de 2025 e degradam graciosamente, portanto é seguro utilizá-las com uma verificação if (document.startViewTransition).

IntersectionObserver: a API web que substitui os listeners de scroll

IntersectionObserver reporta de forma assíncrona quando um elemento-alvo entra ou sai da viewport (ou de qualquer ancestral), permitindo que você implemente lazy-loading, scroll infinito e analytics de visibilidade sem um único listener de scroll — e está disponível como Baseline em todos os browsers desde março de 2019. Listeners de scroll disparam dezenas de vezes por segundo na thread principal e exigem que você calcule a geometria manualmente; o observer agrupa esse trabalho fora do caminho crítico e só o notifica quando a visibilidade realmente muda.

const observer = new IntersectionObserver((entries) => {
  for (const entry of entries) {
    if (entry.isIntersecting) {
      entry.target.src = entry.target.dataset.src; // carrega apenas quando visível
      observer.unobserve(entry.target);
    }
  }
});

document.querySelectorAll('img[data-src]').forEach((img) => observer.observe(img));

Este trecho realiza o lazy-loading de imagens conforme as linhas entram na viewport. A mesma verificação com isIntersecting serve para sentinelas de scroll infinito e analytics de “visualização”. As gravações de sessão em feeds longos tornam o benefício evidente: imagens fora da tela e eventos de rastreamento são resolvidos apenas quando suas respectivas linhas entram na viewport, e não todos de uma vez no carregamento. Substitui react-intersection-observer e cálculos manuais de scroll na maioria dos casos. (Observação: a opção trackVisibility ainda é experimental e não faz parte do Baseline. Use apenas isIntersecting.)

ResizeObserver: reações a redimensionamento no nível do elemento

Utilize ResizeObserver — e não o evento resize da window — sempre que um componente precisar reagir ao seu próprio tamanho: ele reporta mudanças no content-box e no border-box no nível do elemento, o que torna possível a criação de componentes responsivos ao contêiner. Um handler de window.resize informa que a viewport mudou; ele não diz nada sobre um painel que encolheu porque uma barra lateral foi aberta.

const ro = new ResizeObserver((entries) => {
  for (const entry of entries) {
    const { width } = entry.contentRect;
    entry.target.classList.toggle('is-narrow', width < 400);
  }
});

ro.observe(document.querySelector('.card'));

Aqui, o card alterna para um layout compacto com base em sua própria largura — uma container query implementada em JavaScript. Está disponível como Baseline nos browsers modernos e substitui bibliotecas como element-resize-detector. Se você encontrar um aviso ResizeObserver loop no console, ele é geralmente inofensivo e indica que você modificou o tamanho dentro do próprio callback.

AbortController: cancele fetches e corrija race conditions

AbortController é a solução padrão para race conditions no React: passe controller.signal para o fetch, chame controller.abort() no cleanup do seu effect, e uma resposta desatualizada jamais poderá sobrescrever a UI atual após uma navegação rápida. AbortSignal está disponível em todos os browsers desde abril de 2018.

useEffect(() => {
  const controller = new AbortController();
  fetch(`/api/results?q=${query}`, { signal: controller.signal })
    .then((res) => res.json())
    .then(setResults)
    .catch((err) => {
      if (err.name !== 'AbortError') throw err;
    });
  return () => controller.abort(); // cancela ao desmontar ou com nova query
}, [query]);

O bug clássico que isso elimina é aquele que uma gravação de sessão torna evidente: o usuário digita rapidamente, uma resposta lenta anterior chega por último, e dados desatualizados sobrescrevem a view atual. Abortar a requisição em andamento no cleanup torna isso impossível. Para timeouts especificamente, você pode dispensar o controller manual. AbortSignal.timeout() funciona em todos os browsers desde abril de 2024 e aborta com um TimeoutError, enquanto um abort disparado pelo usuário lança AbortError — assim, um único catch consegue distingui-los:

fetch(url, { signal: AbortSignal.timeout(5000) });

Isso substitui flags isMounted e axios.CancelToken.

Clipboard API: copiar para a área de transferência sem o hack do execCommand

navigator.clipboard.writeText() é o substituto moderno, baseado em Promises, para o hack com document.execCommand('copy'). Apenas lembre-se de que ele só funciona em um contexto seguro (HTTPS ou localhost).

copyBtn.addEventListener('click', async () => {
  await navigator.clipboard.writeText(snippet);
  copyBtn.textContent = 'Copiado!';
});

Este é o botão “copiar trecho de código” presente em todo site de documentação. A escrita é Baseline e confiável; a leitura é de melhor esforço. readText() retorna uma string vazia quando a área de transferência não contém texto, e o Firefox a restringe com mais rigor do que a escrita — portanto, copiar é o caminho confiável, enquanto a leitura para colar deve ser tratada como progressive enhancement. Substitui clipboard.js.

View Transitions API: anime mudanças de estado do DOM nativamente

A View Transitions API anima transições entre estados do DOM com document.startViewTransition(() => updateDOM()) e, como degrada graciosamente (sem animação, mas o DOM ainda é atualizado em browsers sem suporte), é seguro utilizá-la hoje com uma verificação if (document.startViewTransition). As transições para o mesmo documento atingiram o status de Baseline Newly available em 14 de outubro de 2025, funcionando no Chrome 111+, Edge 111+, Firefox 144+ e Safari 18+.

function updatePage(newContent) {
  if (!document.startViewTransition) {
    render(newContent); // fallback: atualização imediata, sem animação
    return;
  }
  document.startViewTransition(() => render(newContent));
}

Utilize-a para troca de abas, navegações de lista para detalhe e mudanças de filtro — os crossfades e morphs de elementos compartilhados que você normalmente importaria o Framer Motion para realizar. A verificação com startViewTransition() garante que browsers sem suporte simplesmente apliquem a mudança imediatamente. Observe que as transições entre documentos têm suporte mais restrito: Chrome 126+, Edge 126+ e Safari 18.2+, sem suporte no Firefox ainda — portanto, não confunda as duas.

APIs Bônus: structuredClone e a pegadinha do fetch

Escolha uma dessas APIs na sua próxima tarefa e elimine a dependência que ela substitui: troque um listener de scroll pelo IntersectionObserver, ou envolva um fetch de busca em um AbortController. Uma menção honrosa que vale ter à mão: structuredClone() realiza cópias profundas de objetos sem o round-trip de JSON.parse(JSON.stringify(...)) e preserva Dates, Maps, Sets e typed arrays — embora lance DataCloneError em funções e nós do DOM, portanto é indicado para dados, não para objetos ativos (Baseline desde março de 2022). E se fetch ainda é sua base, lembre-se de que sua Promise não rejeita em HTTP 404 ou 500 — apenas em falhas de rede — portanto verifique response.ok manualmente.

Perguntas Frequentes

Qual é a diferença entre IntersectionObserver e ResizeObserver?

IntersectionObserver reporta quando um elemento entra ou sai da viewport ou de um ancestral, sendo utilizado para lazy-loading, scroll infinito e analytics de visibilidade. ResizeObserver reporta mudanças nas dimensões do content-box ou border-box do próprio elemento, sendo utilizado para layouts responsivos ao contêiner. IntersectionObserver responde à pergunta 'este elemento está visível?', enquanto ResizeObserver responde 'qual é o tamanho deste elemento?'. São perguntas diferentes, e nenhum dos dois substitui o papel do evento resize da window no nível da viewport.

Devo usar AbortSignal.timeout() ou um AbortController manual para cancelar requisições fetch?

Use AbortSignal.timeout() quando você precisar apenas de um timeout fixo, pois ele aborta automaticamente após os milissegundos definidos com um TimeoutError, sem necessidade de uma variável controller. Use um AbortController manual quando o cancelamento for disparado por um evento que você controla, como o cleanup de um effect do React ao desmontar o componente ou ao navegar para outra rota, onde você chama controller.abort() manualmente. Os dois lançam erros diferentes — TimeoutError versus AbortError — portanto um único bloco catch consegue distingui-los.

Por que navigator.clipboard.writeText() falha no meu ambiente de desenvolvimento local?

navigator.clipboard.writeText() só funciona em um contexto seguro, ou seja, HTTPS ou localhost. Se você acessar um servidor de desenvolvimento por um endereço HTTP simples, como um IP local ou um hostname diferente de localhost, o browser bloqueará as escritas na área de transferência e a Promise será rejeitada. Use localhost ou sirva a aplicação via HTTPS. A leitura com readText() é ainda mais restrita, especialmente no Firefox — portanto, trate a escrita como o caminho confiável e a leitura para colar como progressive enhancement.

É seguro usar a View Transitions API se alguns browsers não a suportam?

Sim, porque ela degrada graciosamente. Proteja a chamada com if (document.startViewTransition) antes de invocá-la; em browsers sem suporte, a atualização do DOM ainda ocorre, apenas sem animação. As transições para o mesmo documento atingiram o status de Baseline Newly available em 14 de outubro de 2025, no Chrome 111+, Edge 111+, Firefox 144+ e Safari 18+. As transições entre documentos têm suporte mais restrito: Chrome 126+, Edge 126+ e Safari 18.2+, sem suporte no Firefox ainda.

Open-source session replay

Gain control over your UX

See how users are using your site as if you were sitting next to them, learn and iterate faster with OpenReplay — the open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data.

Star on GitHub12k

We use cookies to improve your experience. By using our site, you accept cookies.