Melhorias na dispensa de páginas em XMLHttpRequest() síncrono

Reduzir a navegação atrasada

Joe Medley
Joe Medley

É comum que uma página ou um app tenha análises ou outros dados não enviados no momento em que o usuário os fecha. Para evitar a perda de dados, alguns sites usam uma chamada síncrona para XMLHttpRequest() a fim de manter a página ou o app aberto até que os dados sejam transmitidos ao servidor. Além de haver maneiras melhores de salvar dados, essa técnica cria uma experiência ruim para o usuário, atrasando o fechamento da página por até vários segundos.

Essa prática precisa mudar, e os navegadores estão reagindo. A especificação XMLHttpRequest() já está programada para descontinuação e remoção. O Chrome 80 dá o primeiro passo ao proibir chamadas síncronas em vários manipuladores de eventos, especificamente beforeunload, unload, pagehide e visibilitychange, quando são acionados na dispensa. O WebKit também fez uma confirmação que implementa a mesma mudança de comportamento.

Neste artigo, vamos descrever brevemente as opções para quem precisa de tempo para atualizar os sites e resumir as alternativas para XMLHttpRequest().

Desativações temporárias

O Chrome não quer simplesmente desativar o XMLHttpRequest(). Por isso, algumas opções temporárias de desativação estão disponíveis. Para sites na Internet, um teste de origem está disponível. Com isso, você adiciona um token específico da origem aos cabeçalhos da página que ativa chamadas XMLHttpRequest() síncronas. Essa opção vai ser desativada pouco antes do lançamento do Chrome 89, em algum momento de março de 2021. Os clientes do Chrome Enterprise também podem usar a flag de política AllowSyncXHRInPageDismissal, que termina no mesmo período.

Alternativas

Independentemente de como você envia dados de volta ao servidor, é melhor evitar esperar até a página ser descarregada para enviar todos os dados de uma só vez. Além de criar uma experiência ruim para o usuário, o descarregamento não é confiável em navegadores modernos e corre o risco de perda de dados se algo der errado. Especificamente, os eventos de descarregamento geralmente não são acionados em navegadores para dispositivos móveis porque há muitas maneiras de fechar uma aba ou um navegador em sistemas operacionais para dispositivos móveis sem que o evento unload seja acionado. Com XMLHttpRequest(), usar payloads pequenos era uma opção. Agora é um requisito. As duas alternativas têm um limite de upload de 64 KB por contexto, conforme exigido pela especificação.

Buscar indicador de atividade

A API Fetch oferece um meio robusto de lidar com interações do servidor e uma interface consistente para uso em diferentes APIs de plataforma. Entre as opções está keepalive, que garante que uma solicitação continue aberta mesmo que a página que a fez fique aberta:

window.addEventListener('unload', {
  fetch('/siteAnalytics', {
    method: 'POST',
    body: getStatistics(),
    keepalive: true
  });
}

O método fetch() tem a vantagem de ter maior controle sobre o que é enviado ao servidor. O que não mostro no exemplo é que fetch() também retorna uma promessa que é resolvida com um objeto Response. Como estou tentando sair do caminho da transferência da página, decidi não fazer nada com ela.

SendBeacon()

Na verdade, o SendBeacon() usa a API Fetch em segundo plano, e é por isso que ela tem a mesma limitação de payload de 64 KB e também garante que uma solicitação continue após o descarregamento de uma página. Sua principal vantagem é a simplicidade. Ele permite enviar seus dados com uma única linha de código:

window.addEventListener('unload', {
  navigator.sendBeacon('/siteAnalytics', getStatistics());
}

Conclusão

Com o aumento da disponibilidade de fetch() em vários navegadores, esperamos que o XMLHttpRequest() seja removido da plataforma da Web em algum momento. Os fornecedores de navegadores concordam que ele precisa ser removido, mas isso vai levar tempo. A descontinuação de um dos piores casos de uso é uma primeira etapa que melhora a experiência do usuário para todos.

Foto de Matthew Hamilton no Unsplash