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 partes curtas de trabalho, como o envio de uma mensagem. No entanto, se a tarefa demorar muito, o navegador vai encerrar o service worker. Caso contrário, há um risco à privacidade e à 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.
Esta é uma demonstração rápida de dois minutos que mostra o estado tradicional das coisas em comparação com o uso da Busca em segundo plano:
Experimente a demonstração e navegue pelo código.
Como funciona
Uma busca em segundo plano funciona da seguinte maneira:
- Você instrui o navegador a executar um grupo de buscas em segundo plano.
- O navegador busca essas coisas, mostrando o progresso ao 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 for o caso.
Se o usuário fechar as páginas do seu site após a etapa 1, não tem problema, o download continuará. Como a busca é altamente visível e facilmente cancelável, não há a preocupação de privacidade de uma tarefa de sincronização em segundo plano longa demais. Como o service worker não está em execução constantemente, não há a preocupação de que ele possa abusar do sistema, como a mineração de bitcoin em segundo plano.
Em algumas plataformas (como o Android), é possível que o navegador seja fechado após a etapa 1, já que o navegador pode transferir a busca para o sistema operacional.
Se o usuário iniciar o download enquanto estiver 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 recurso
Como acontece com qualquer recurso novo, você quer detectar se o navegador é compatível. 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 trava o registro de um service worker. Portanto, primeiro registre um service worker. Depois:
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>
O que será buscado As strings serão tratadas como URLs e transformadas em Request s por meio de new Request(theString) .
É possível buscar itens de outras origens, desde que os recursos permitam isso usando o CORS. Observação: atualmente, o Chrome não aceita solicitações que exijam uma simulação do CORS. |
options |
Um objeto que pode incluir o seguinte: |
options.title |
string Um título para o navegador mostrar 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 descompactar com gzip). Embora seja opcional, é altamente recomendável que você a forneça. Ele é usado para informar ao usuário o tamanho do download e fornecer informações de progresso. Se você não fornecer essa informação, o navegador vai informar ao usuário que o tamanho é desconhecido e, como resultado, o usuário poderá cancelar o download. Se os downloads de busca em segundo plano excederem o número fornecido aqui, ela será cancelada. Não há problema se o download for menor que o |
backgroundFetch.fetch
retorna uma promessa que é resolvida com um BackgroundFetchRegistration
. Falarei sobre isso
mais tarde. A promessa vai ser rejeitada se o usuário tiver desativado os downloads ou um dos parâmetros fornecidos for inválido.
Fornecer muitas solicitações para uma única busca em segundo plano permite combinar coisas que, logicamente, são únicas para o usuário. Por exemplo, um filme pode ser dividido em milhares de recursos (típico com MPEG-DASH) e vir com recursos adicionais, como imagens. Um nível de 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 conseguir uma busca em segundo plano existente
É possível conseguir uma busca em segundo plano existente como esta:
navigator.serviceWorker.ready.then(async (swReg) => {
const bgFetch = await swReg.backgroundFetch.get('my-fetch');
});
... passando o id da busca em segundo plano que você quiser. get
vai retornar undefined
se não houver
uma busca ativa em segundo plano com esse ID.
Uma busca em segundo plano é considerada "ativa" a partir do momento em que é registrada, até que seja concluída, falhar ou ser cancelada.
Veja uma lista de todas as buscas ativas em segundo plano usando getIds
:
navigator.serviceWorker.ready.then(async (swReg) => {
const ids = await swReg.backgroundFetch.getIds();
});
Registros de busca em segundo plano
Uma 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 desse recurso do zero. |
result |
Opções:
|
failureReason |
Opções:
|
recordsAvailable |
boolean É possível acessar as solicitações/respostas subjacentes? Se ele for falso, |
Métodos | |
abort() |
Retorna Promise<boolean> Cancelar a busca em segundo plano. A promessa retornada é resolvida com true se a busca foi cancelada com sucesso. |
matchAll(request, opts) |
Retorna Promise<Array<BackgroundFetchRecord>> Receba as solicitações e respostas. Os argumentos são iguais aos 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 é resolvido com a primeira correspondência. |
Eventos | |
progress |
Disparado quando qualquer uploaded , downloaded , result ou
failureReason muda. |
Como acompanhar o progresso
Isso pode ser feito pelo evento progress
. Lembre-se de que downloadTotal
é o valor que você
forneceu, ou 0
caso você não tenha 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 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);
});
A record
é uma BackgroundFetchRecord
e tem esta aparência:
Propriedades | |
---|---|
request |
Request A solicitação que foi fornecida. |
responseReady |
Promise<Response> A resposta buscada. A resposta é prometida e pode não ter sido recebida ainda. A promessa vai ser rejeitada se a busca falhar. |
Eventos de service worker
Eventos | |
---|---|
backgroundfetchsuccess |
Tudo foi buscado. |
backgroundfetchfailure |
Falha em uma ou mais buscas. |
backgroundfetchabort |
Falha em uma ou mais buscas.
Isso só é realmente útil se você deseja realizar a limpeza de 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 alterar o título/ícones que você definiu inicialmente. Isso é opcional, mas permite que você forneça mais contexto, se necessário. Só é possível fazer isso *uma vez* durante os eventos backgroundfetchsuccess e backgroundfetchfailure . |
Como reagir a sucessos/falhas
Já vimos o evento progress
, mas ele só é útil enquanto o usuário tem uma página aberta para
o site. O principal benefício da busca 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 receberá o
evento backgroundfetchsuccess
, e event.registration
será o registro da busca em segundo plano.
Após esse evento, as solicitações e respostas buscadas não poderão mais ser acessadas. Portanto, se você quiser mantê-las, mova-as para algum lugar como a API de cache.
Como na maioria dos eventos de service worker, use event.waitUntil
para que o service worker saiba quando o evento
está concluído.
Por exemplo, no service worker:
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!' });
}());
});
As falhas podem ter se voltado a um único erro 404, o que pode não ter sido importante para você. Por isso, ainda pode valer a pena copiar algumas respostas em um cache, conforme mostrado acima.
Reagindo ao clique
É possível clicar na interface que mostra o progresso e o resultado do download. O evento backgroundfetchclick
no
service worker permite que você reaja a isso. Assim como acima, event.registration
será o registro da
busca em segundo plano.
A coisa mais comum a fazer com esse evento é abrir 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 fazia referência incorreta à Busca em segundo plano como um "padrão da Web". No momento, a API não está seguindo os padrões. A especificação pode ser encontrada nas WICG como um rascunho do relatório do grupo comunitário.