É comum que as páginas da Web precisem enviar dados (ou "beacon") de volta ao servidor. Pense nos dados de análise da sessão atual de um usuário, por exemplo. Para os desenvolvedores, isso exige um equilíbrio: reduzir solicitações constantes e possivelmente redundantes sem arriscar a perda de dados se a guia for fechada ou o usuário sair antes que um beacon seja enviado.
Tradicionalmente, os desenvolvedores usam eventos pagehide
e visibilitychange
para capturar a página durante o descarregamento e, em seguida, usar navigator.sendBeacon()
ou fetch()
com keepalive
para fazer o beacon dos dados. No entanto, esses dois eventos têm casos específicos difíceis que diferem com base no navegador do usuário e, às vezes, os eventos nunca chegam, especialmente no dispositivo móvel.
fetchLater()
é uma proposta para substituir essa complexidade por uma única chamada de API. Ele faz exatamente como o nome sugere: solicita que o navegador garanta que uma solicitação seja feita em algum momento no futuro, mesmo que a página seja fechada ou que o usuário saia da página.
fetchLater()
está disponível no Chrome para testes com usuários reais em um teste de origem a partir da versão 121 (lançada em janeiro de 2024) e vai durar até 3 de setembro de 2024.
A API fetchLater()
const fetchLaterResult = fetchLater(request, options);
fetchLater()
usa dois argumentos, geralmente idênticos aos de fetch()
:
- O
request
, um URL de string ou uma instância deRequest
. - Um objeto
options
opcional, que estende ooptions
defetch()
com um tempo limite chamadoactivateAfter
.
fetchLater()
retorna um FetchLaterResult
, que atualmente contém apenas uma única propriedade somente leitura activated
, que será definida como true
quando "mais tarde" tiver sido transmitido e a busca tiver sido feita. Qualquer resposta à solicitação fetchLater()
é descartada.
request
O uso mais simples é um URL sozinho:
fetchLater('/endpoint/');
No entanto, assim como em fetch()
, um grande número de opções pode ser definido em uma solicitação fetchLater()
, incluindo cabeçalhos personalizados, comportamento de credenciais, um corpo POST
e um AbortController
signal
para potencialmente cancelá-la.
fetchLater('/endpoint/', {
method: 'GET',
cache: 'no-store',
mode: 'same-origin',
headers: {Authorization: 'SUPER_SECRET'},
});
options
O objeto de opções estende as opções de fetch()
com um tempo limite, activateAfter
, caso você queira disparar a solicitação após o tempo limite ou quando a página for descarregada, o que ocorrer primeiro.
Assim, é possível decidir o equilíbrio entre ter acesso aos dados no último momento possível ou quando é mais oportuno.
Por exemplo, se você tem um aplicativo que os usuários geralmente mantêm aberto durante todo o dia de trabalho, convém definir um tempo limite de uma hora para garantir análises mais detalhadas e, ao mesmo tempo, garantir um sensor se o usuário sair a qualquer momento antes do término dessa hora. Uma nova fetchLater()
pode ser configurada para a próxima hora de análise.
const hourInMilliseconds = 60 * 60 * 1000;
fetchLater('/endpoint/', {activateAfter: hourInMilliseconds});
Exemplo de uso
Um problema ao medir as Core Web Vitals no campo é que qualquer uma das métricas de performance pode mudar até que o usuário realmente saia de uma página. Por exemplo, mudanças maiores no layout podem acontecer a qualquer momento, ou a página pode levar ainda mais tempo para responder a uma interação.
No entanto, você não quer correr o risco de perder todos os dados de desempenho devido a um beacon com bugs ou incompleto no encerramento da página. É o candidato perfeito para fetchLater()
.
Neste exemplo, a biblioteca web-vitals.js é usada para monitorar as métricas, e fetchLater()
é usada para informar os resultados a um endpoint de análise:
import {onCLS, onINP, onLCP} from 'web-vitals';
const queue = new Set();
let fetchLaterController;
let fetchLaterResult;
function updateQueue(metricUpdate) {
// If there was an already complete request for whatever
// reason, clear out the queue of already-sent updates.
if (fetchLaterResult?.activated) {
queue.clear();
}
queue.add(metricUpdate);
// JSON.stringify used here for simplicity and will likely include
// more data than you need. Replace with a preferred serialization.
const body = JSON.stringify([...queue]);
// Abort any existing `fetchLater()` and schedule a new one with
// the update included.
fetchLaterController?.abort();
fetchLaterController = new AbortController();
fetchLaterResult = fetchLater('/analytics', {
method: 'POST',
body,
signal: fetchLaterController.signal,
activateAfter: 60 * 60 * 1000, // Timeout to ensure timeliness.
});
}
onCLS(updateQueue);
onINP(updateQueue);
onLCP(updateQueue);
Sempre que uma atualização de métrica é recebida, qualquer fetchLater()
programado atual é cancelado com uma AbortController
, e um novo fetchLater()
é criado com a atualização incluída.
Teste o fetchLater()
Como mencionado, fetchLater()
está disponível em um teste de origem até o Chrome 126. Consulte Começar a usar testes de origem para ver informações básicas sobre eles.
Para testes locais, fetchLater
pode ser ativado com a flag de recursos experimentais da plataforma da Web em chrome://flags/#enable-experimental-web-platform-features
. Também é possível ativar esse recurso executando o Chrome na linha de comando com --enable-experimental-web-platform-features
ou a sinalização --enable-features=FetchLaterAPI
mais direcionada.
Se você usar o recurso em uma página pública, verifique se o fetchLater
global está definido antes de usá-lo:
if (globalThis.fetchLater) {
// Set up beaconing using fetchLater().
// ...
}
Feedback
O feedback dos desenvolvedores é essencial para que as novas APIs da Web funcionem corretamente. Registre problemas e feedback no GitHub.