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 mensagem, clicar em "Enviar" e sair do site sabendo que a mensagem será enviada agora ou quando tenham conectividade.
É um recurso útil, mas exige que o service worker esteja ativo pela duração do buscar. Isso não é um problema para pequenas partes de trabalho, como enviar uma mensagem, mas se a tarefa leva muito tempo o navegador eliminará o service worker, caso contrário é um risco para a privacidade do usuário e bateria.
E se você precisar fazer o download de algo que pode demorar muito, como um filme, podcasts ou fases 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.
Aqui está 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 procure o 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 ao usuário.
- Após a conclusão ou falha da busca, o navegador abre seu service worker e aciona um evento para contar o que aconteceu. É aqui que você decide o que fazer com as respostas, se houver.
Se o usuário fechar as páginas do site após a etapa 1, tudo bem, o download continuará. Devido ao a busca for altamente visível e facilmente cancelada, não há a preocupação de privacidade de sincronização em segundo plano. Como o service worker não está em execução constantemente, não há o problema que pode abusar do sistema, por exemplo, minerar bitcoin em segundo plano.
Em algumas plataformas (como Android), é possível que o navegador feche após a etapa 1, pois o navegador pode transferir a busca ao sistema operacional.
Se o usuário iniciar o download enquanto estiver off-line, ou ficar off-line durante o download, o plano de fundo busca será pausada e retomada mais tarde.
A API
Detecção de recursos
Como acontece com qualquer novo recurso, o objetivo é detectar se o navegador é compatível. Para a Busca em segundo plano, tão simples quanto:
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, não deixe de registrar 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. O |
requests |
Array<Request|string>
Itens a serem buscados. As strings serão tratadas como URLs e transformadas em Request por new Request(theString) .
É possível buscar itens de outras origens, desde que os recursos permitam CORS: Observação: no momento, o Chrome não é compatível com solicitações exigem uma simulação do CORS. |
options |
Um objeto que pode incluir o seguinte: |
options.title |
string Um título para o navegador exibir ao longo do progresso. |
options.icons |
Array<IconDefinition> Uma matriz de objetos com "src", "size" e "type". |
options.downloadTotal |
number O tamanho total dos corpos das respostas (após serem descompactadas com gzip). Embora isso seja opcional, recomendamos que você o forneça. É usada para dizer ao usuário o tamanho do download e fornecer informações sobre o andamento. Se você não fornecer isso, o navegador dirá ao usuário que o tamanho é desconhecido e, como resultado, o usuário pode ser mais provavelmente abortará o download. Se os downloads da busca em segundo plano excederem o número indicado aqui, eles serão cancelados. Está
tudo bem se o download for menor que |
backgroundFetch.fetch
retorna uma promessa que é resolvida com uma BackgroundFetchRegistration
. Vou
abordar os detalhes disso mais tarde. A promessa será rejeitada se o usuário tiver desativado os downloads ou
dos parâmetros fornecidos é inválido.
Fornecer muitas solicitações para uma única busca em segundo plano permite combinar coisas que são logicamente uma algo único para o usuário. Por exemplo, um filme pode ser dividido em milhares de recursos (comum MPEG-DASH), e vêm com recursos adicionais, como imagens. Um nível de um jogo pode ser distribuído por vários JavaScript, imagem e recursos de áudio. Mas, para o usuário, é apenas "o filme" ou "o nível".
Como receber uma busca em segundo plano existente
É possível receber uma busca em segundo plano já 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ê quer. get
retorna undefined
se não houver
busca ativa em segundo plano com esse ID.
Uma busca em segundo plano é considerada "ativa" a partir do momento do registro até que dê certo, falhar ou for abortada.
Confira uma lista de todas as buscas em segundo plano ativas 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 e nesse caso o navegador reinicia a busca desse recurso do zero. |
result |
Opções:
|
failureReason |
Opções:
|
recordsAvailable |
boolean É possível acessar as solicitações/respostas subjacentes? Se for falso, |
Métodos | |
abort() |
Retorna Promise<boolean> Cancela a busca em segundo plano. A promessa retornada é resolvida com "true" se a busca for cancelada. |
matchAll(request, opts) |
Retorna Promise<Array<BackgroundFetchRecord>> Receber as solicitações e respostas. Os argumentos aqui são os mesmos que o cache API. 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 |
Disparado quando uploaded , downloaded , result ou
failureReason alteração. |
Acompanhamento do progresso
Isso pode ser feito no evento progress
. Lembre-se de que downloadTotal
é o valor que você
fornecido, 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 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 esta aparência:
Propriedades | |
---|---|
request |
Request A solicitação que foi enviada. |
responseReady |
Promise<Response> A resposta buscada. A resposta está por trás de uma promessa porque talvez ela ainda não tenha sido recebida. A promessa será rejeitada se a busca falhar. |
Eventos de service worker
Eventos | |
---|---|
backgroundfetchsuccess |
A busca foi concluída. |
backgroundfetchfailure |
Falha em uma ou mais buscas. |
backgroundfetchabort |
Falha em uma ou mais buscas.
Isso é realmente útil apenas se você deseja realizar uma 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 mudar o título/ícones definidos inicialmente. Isso é opcional, mas permite que você
fornecer mais contexto, se necessário. Você só pode fazer isso *uma vez* durante
Eventos backgroundfetchsuccess e backgroundfetchfailure . |
Reagir ao sucesso/fracasso
Já vimos o evento progress
, mas ele só é útil enquanto o usuário está com uma página aberta para
seu site. O principal benefício da busca em segundo plano é que as coisas continuam funcionando depois que o usuário sai da
ou até mesmo fechar o navegador.
Se a busca em segundo plano for concluída, o service worker receberá a
backgroundfetchsuccess
e event.registration
serão o registro de busca em segundo plano.
Após esse evento, as solicitações e respostas buscadas não estarão mais acessíveis, portanto, se você quiser mova-os 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
é concluída.
Por exemplo, no seu 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!' });
}());
});
A falha pode ter se reduzido a um único erro 404, que pode não ter sido importante para você, então pode ainda vale a pena copiar algumas respostas em um cache, como mostrado acima.
Reagir ao clique
É possível clicar na interface que exibe o progresso do download e o resultado. O evento backgroundfetchclick
em
o service worker permite que você reaja a isso. Assim como acima, event.registration
será o plano de fundo
registro de busca.
Normalmente, 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 fez referência incorreta à Busca em segundo plano de "padrão da Web". No momento, a API não está na faixa padrão. A especificação pode ser encontrada no WICG como um rascunho de relatório do grupo da comunidade.