Em 2015, lançamos a sincronização em segundo plano, que permite que o service worker adie o trabalho até que o usuário tenha conectividade. Isso significa que o usuário pode digitar uma mensagem, clicar em enviar e sair do site sabendo que a mensagem será enviada agora ou quando ele tiver conectividade.
É um recurso útil, mas exige que o service worker esteja ativo durante a busca. Isso não é um problema para trabalhos curtos, como enviar uma mensagem, mas, se a tarefa demorar demais, o navegador vai encerrar o worker do serviço. Caso contrário, isso representa um risco para a privacidade e a bateria do usuário.
E se você precisar fazer o download de algo que pode levar muito tempo, como um filme, podcasts ou níveis de um jogo? É para isso que serve a busca em segundo plano.
A busca em segundo plano está disponível por padrão desde o Chrome 74.
Confira uma demonstração rápida de dois minutos mostrando o estado tradicional das coisas em comparação com o uso do fetch em segundo plano:
Teste a demonstração e navegue pelo código.
Como funciona
Uma busca em segundo plano funciona assim:
- Você informa ao navegador para executar um grupo de buscas em segundo plano.
- O navegador busca esses itens, mostrando o progresso para o usuário.
- Depois que a busca é concluída ou falha, o navegador abre o service worker e dispara um evento para informar o que aconteceu. É aqui que você decide o que fazer com as respostas, se houver alguma.
Se o usuário fechar as páginas do seu site após a etapa 1, não tem problema. O download vai continuar. Como a busca é altamente visível e pode ser facilmente abortada, não há preocupação com a privacidade de uma tarefa de sincronização em segundo plano muito longa. Como o service worker não está em execução constantemente, não há preocupação de que ele possa abusar do sistema, como a mineração de bitcoins em segundo plano.
Em algumas plataformas (como o Android), é possível que o navegador seja fechado após a etapa 1, já que ele pode transferir a busca para o sistema operacional.
Se o usuário iniciar o download off-line ou ficar off-line durante o download, a busca em segundo plano será pausada e retomada mais tarde.
A API
Detecção de recursos
Como acontece com qualquer novo recurso, você precisa detectar se o navegador oferece suporte a ele. Para a Busca em segundo plano, é simples:
if ('BackgroundFetchManager' in self) {
// This browser supports Background Fetch!
}
Como iniciar uma busca em segundo plano
A API principal depende de um registro de service worker. Portanto, registre um service worker primeiro. Em seguida:
navigator.serviceWorker.ready.then(async (swReg) => {
const bgFetch = await swReg.backgroundFetch.fetch('my-fetch', ['/ep-5.mp3', 'ep-5-artwork.jpg'], {
title: 'Episode 5: Interesting things.',
icons: [{
sizes: '300x300',
src: '/ep-5-icon.png',
type: 'image/png',
}],
downloadTotal: 60 * 1024 * 1024,
});
});
backgroundFetch.fetch
usa três argumentos:
Parâmetros | |
---|---|
id |
string identifica de forma exclusiva essa busca em segundo plano.
|
requests |
Array<Request|string>
As coisas a serem buscadas. As strings serão tratadas como URLs e transformadas em Request s usando new Request(theString) .
É possível buscar coisas de outras origens, desde que os recursos permitam isso pelo CORS. Observação:no momento, o Chrome não oferece suporte a solicitações que exigem um pré-lançamento do CORS. |
options |
Um objeto que pode incluir o seguinte: |
options.title |
string Um título para o navegador mostrar junto com o progresso. |
options.icons |
Array<IconDefinition> Uma matriz de objetos com "src", "size" e "type". |
options.downloadTotal |
number O tamanho total dos corpos de resposta (depois de descompactados). Embora isso seja opcional, é altamente recomendável que você forneça. Ele é usado para informar ao usuário o tamanho do download e fornecer informações sobre o progresso. Se você não fornecer essa informação, o navegador vai informar ao usuário que o tamanho é desconhecido. Como resultado, o usuário pode ter mais probabilidade de interromper o download. Se os downloads de busca em segundo plano excederem o número indicado aqui, eles serão abortados. Não há
problema se o download for menor que o |
backgroundFetch.fetch
retorna uma promessa que é resolvida com um BackgroundFetchRegistration
. Vou
falar sobre os detalhes disso mais tarde. A promessa é rejeitada se o usuário tiver desativado os downloads ou se um
dos parâmetros fornecidos for inválido.
Fornecer muitas solicitações para uma única busca em segundo plano permite combinar coisas que são logicamente uma única coisa para o usuário. Por exemplo, um filme pode ser dividido em milhares de recursos (típico com MPEG-DASH) e ter recursos adicionais, como imagens. Um nível de um jogo pode ser distribuído por muitos recursos de JavaScript, imagem e áudio. Mas, para o usuário, é apenas "o filme" ou "o nível".
Como receber uma busca em segundo plano
É possível fazer uma busca em segundo plano existente desta forma:
navigator.serviceWorker.ready.then(async (swReg) => {
const bgFetch = await swReg.backgroundFetch.get('my-fetch');
});
…transmitindo o ID da busca em segundo plano que você quer. get
retorna undefined
se não houver
uma busca em segundo plano ativa com esse ID.
Uma busca em segundo plano é considerada "ativa" desde o momento em que é registrada até que seja concluída, falha ou seja interrompida.
É possível conferir uma lista de todas as transferências em segundo plano ativas usando getIds
:
navigator.serviceWorker.ready.then(async (swReg) => {
const ids = await swReg.backgroundFetch.getIds();
});
Registros de busca em segundo plano
Um BackgroundFetchRegistration
(bgFetch
nos exemplos acima) tem o seguinte:
Propriedades | |
---|---|
id |
string O ID da busca em segundo plano. |
uploadTotal |
number O número de bytes a serem enviados ao servidor. |
uploaded |
number O número de bytes enviados. |
downloadTotal |
number O valor fornecido quando a busca em segundo plano foi registrada ou zero. |
downloaded |
number O número de bytes recebidos. Esse valor pode diminuir. Por exemplo, se a conexão cair e o download não puder ser retomado, o navegador vai reiniciar a busca do recurso do zero. |
result |
Opções:
|
failureReason |
Opções:
|
recordsAvailable |
boolean As solicitações/respostas podem ser acessadas? Quando esse valor for falso, |
Métodos | |
abort() |
Retorna Promise<boolean> Interrompe a busca em segundo plano. A promessa retornada é resolvida com "true" se a busca foi interrompida. |
matchAll(request, opts) |
Retorna Promise<Array<BackgroundFetchRecord>> Receba as solicitações e respostas. Os argumentos aqui são os mesmos da API de cache. Chamar sem argumentos retorna uma promessa para todos os registros. Veja mais detalhes abaixo. |
match(request, opts) |
Retorna Promise<BackgroundFetchRecord> como acima, mas resolve com a primeira correspondência. |
Eventos | |
progress |
É acionado quando qualquer um dos valores uploaded , downloaded , result ou
failureReason muda. |
Acompanhamento do progresso
Isso pode ser feito pelo evento progress
. Lembre-se de que downloadTotal
é qualquer valor que você
forneceu ou 0
se você não tiver fornecido um valor.
bgFetch.addEventListener('progress', () => {
// If we didn't provide a total, we can't provide a %.
if (!bgFetch.downloadTotal) return;
const percent = Math.round(bgFetch.downloaded / bgFetch.downloadTotal * 100);
console.log(`Download progress: ${percent}%`);
});
Como receber as solicitações e respostas
bgFetch.match('/ep-5.mp3').then(async (record) => {
if (!record) {
console.log('No record found');
return;
}
console.log(`Here's the request`, record.request);
const response = await record.responseReady;
console.log(`And here's the response`, response);
});
record
é um BackgroundFetchRecord
e tem este formato:
Propriedades | |
---|---|
request |
Request A solicitação que foi enviada. |
responseReady |
Promise<Response> A resposta buscada. A resposta está atrás de uma promessa porque talvez ainda não tenha sido recebida. A promessa será rejeitada se a busca falhar. |
Eventos de service worker
Eventos | |
---|---|
backgroundfetchsuccess |
Tudo foi buscado com sucesso. |
backgroundfetchfailure |
Uma ou mais transferências falharam. |
backgroundfetchabort |
Um ou mais downloads falharam.
Isso é útil apenas se você quiser limpar dados relacionados. |
backgroundfetchclick |
O usuário clicou na interface de progresso do download. |
Os objetos de evento têm o seguinte:
Propriedades | |
---|---|
registration |
BackgroundFetchRegistration |
Métodos | |
updateUI({ title, icons }) |
Permite mudar o título/ícones definidos inicialmente. Isso é opcional, mas permite
fornecer mais contexto, se necessário. Você só pode fazer isso *uma vez* durante os eventos backgroundfetchsuccess e backgroundfetchfailure . |
Reagir a sucesso/falha
Já abordamos o evento progress
, mas ele só é útil enquanto o usuário tem uma página aberta no seu site. O principal benefício do fetch em segundo plano é que as coisas continuam funcionando depois que o usuário sai da
página ou até mesmo fecha o navegador.
Se a busca em segundo plano for concluída, o service worker vai receber o evento
backgroundfetchsuccess
, e event.registration
será o registro da busca em segundo plano.
Depois desse evento, as solicitações e respostas buscadas não são mais acessíveis. Se você quiser mantê-las, mova-as para algum lugar, como a API de cache.
Como na maioria dos eventos do service worker, use event.waitUntil
para que o service worker saiba quando o evento
for concluído.
Por exemplo, no seu worker de serviço:
addEventListener('backgroundfetchsuccess', (event) => {
const bgFetch = event.registration;
event.waitUntil(async function() {
// Create/open a cache.
const cache = await caches.open('downloads');
// Get all the records.
const records = await bgFetch.matchAll();
// Copy each request/response across.
const promises = records.map(async (record) => {
const response = await record.responseReady;
await cache.put(record.request, response);
});
// Wait for the copying to complete.
await Promise.all(promises);
// Update the progress notification.
event.updateUI({ title: 'Episode 5 ready to listen!' });
}());
});
A falha pode ter sido causada por um único erro 404, que pode não ter sido importante para você. Portanto, pode ainda valer a pena copiar algumas respostas para um cache, como acima.
Reação a cliques
A interface que mostra o progresso e o resultado do download é clicável. O evento backgroundfetchclick
no
service worker permite reagir a isso. Como acima, event.registration
será o registro de busca
em segundo plano.
O que geralmente acontece com esse evento é a abertura de uma janela:
addEventListener('backgroundfetchclick', (event) => {
const bgFetch = event.registration;
if (bgFetch.result === 'success') {
clients.openWindow('/latest-podcasts');
} else {
clients.openWindow('/download-progress');
}
});
Outros recursos
Correção: uma versão anterior deste artigo se referia incorretamente ao fetch em segundo plano como um "padrão da Web". No momento, a API não está no padrão, e a especificação pode ser encontrada no WICG como um rascunho do relatório do grupo da comunidade.