En 2015, presentamos la Sincronización en segundo plano, que permite que el trabajador de servicio posponga el trabajo hasta que el usuario tenga conectividad. Esto significa que el usuario podría escribir un mensaje, presionar Enviar y salir del sitio sabiendo que el mensaje se enviará ahora o cuando tenga conectividad.
Es una función útil, pero requiere que el service worker esté activo durante la recuperación. Esto no es un problema para tareas cortas, como enviar un mensaje, pero si la tarea tarda demasiado, el navegador cerrará el service worker, ya que, de lo contrario, se pondría en riesgo la privacidad y la batería del usuario.
¿Qué sucede si necesitas descargar algo que podría tardar mucho tiempo, como una película, podcasts o niveles de un juego? Para eso sirve la recuperación en segundo plano.
Background Fetch está disponible de forma predeterminada desde Chrome 74.
A continuación, se incluye una demostración rápida de dos minutos que muestra el estado tradicional de las cosas en comparación con el uso de Background Fetch:
Cómo funciona
Una recuperación en segundo plano funciona de la siguiente manera:
- Le indicas al navegador que realice un grupo de recuperaciones en segundo plano.
- El navegador recupera esos elementos y le muestra el progreso al usuario.
- Una vez que se completa o falla la recuperación, el navegador abre tu service worker y activa un evento para informarte lo que sucedió. Aquí es donde decides qué hacer con las respuestas, si es que hay algo que hacer.
Si el usuario cierra las páginas de tu sitio después del paso 1, no hay problema, la descarga continuará. Dado que la recuperación es muy visible y se puede anular fácilmente, no existe el problema de privacidad de una tarea de sincronización en segundo plano demasiado larga. Como el service worker no se ejecuta de forma constante, no hay riesgo de que abuse del sistema, por ejemplo, minando bitcoins en segundo plano.
En algunas plataformas (como Android), es posible que el navegador se cierre después del paso 1, ya que puede transferir la recuperación al sistema operativo.
Si el usuario inicia la descarga sin conexión o se queda sin conexión durante la descarga, la recuperación en segundo plano se pausará y se reanudará más tarde.
La API
Detección de funciones
Al igual que con cualquier función nueva, debes detectar si el navegador la admite. Para la recuperación en segundo plano, es tan simple como lo siguiente:
if ('BackgroundFetchManager' in self) {
// This browser supports Background Fetch!
}
Cómo iniciar una recuperación en segundo plano
La API principal depende del registro de un service worker, por lo que debes asegurarte de registrar uno primero. Luego:
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
toma tres argumentos:
Parámetros | |
---|---|
id |
string identifica de forma única esta recuperación en segundo plano.
|
requests |
Array<Request|string>
Elementos que se recuperarán. Las cadenas se tratarán como URLs y se convertirán en objetos Request a través de new Request(theString) .
Puedes recuperar elementos de otros orígenes siempre y cuando los recursos lo permitan a través de CORS. Nota: Actualmente, Chrome no admite solicitudes que requerirían una comprobación previa de CORS. |
options |
Es un objeto que puede incluir lo siguiente: |
options.title |
string Título que el navegador mostrará junto con el progreso. |
options.icons |
Array<IconDefinition> Es un array de objetos con "src", "size" y "type". |
options.downloadTotal |
number Tamaño total de los cuerpos de respuesta (después de descomprimirse con gzip). Aunque es opcional, te recomendamos que lo proporciones. Se usa para indicarle al usuario el tamaño de la descarga y proporcionar información sobre el progreso. Si no proporcionas esta información, el navegador le indicará al usuario que el tamaño es desconocido y, como resultado, es más probable que el usuario cancele la descarga. Si las descargas de recuperación en segundo plano superan la cantidad que se indica aquí, se anularán. No hay problema si la descarga es más pequeña que |
backgroundFetch.fetch
devuelve una promesa que se resuelve con un BackgroundFetchRegistration
. Explicaré los detalles más adelante. La promesa se rechaza si el usuario inhabilitó las descargas o si uno de los parámetros proporcionados no es válido.
Proporcionar muchas solicitudes para una sola recuperación en segundo plano te permite combinar elementos que, lógicamente, son una sola cosa para el usuario. Por ejemplo, una película se puede dividir en miles de recursos (lo que es típico con MPEG-DASH) y venir con recursos adicionales, como imágenes. Un nivel de un juego podría distribuirse en muchos recursos de JavaScript, imágenes y audio. Pero para el usuario, es solo "la película" o "el nivel".
Cómo obtener una recuperación en segundo plano existente
Puedes obtener una recuperación en segundo plano existente de la siguiente manera:
navigator.serviceWorker.ready.then(async (swReg) => {
const bgFetch = await swReg.backgroundFetch.get('my-fetch');
});
… pasando el id de la recuperación en segundo plano que desees. get
devuelve undefined
si no hay una recuperación en segundo plano activa con ese ID.
Se considera que una recuperación en segundo plano está "activa" desde el momento en que se registra hasta que se completa, falla o se anula.
Puedes obtener una lista de todas las recuperaciones en segundo plano activas con getIds
:
navigator.serviceWorker.ready.then(async (swReg) => {
const ids = await swReg.backgroundFetch.getIds();
});
Registros de recuperación en segundo plano
Un BackgroundFetchRegistration
(bgFetch
en los ejemplos anteriores) tiene lo siguiente:
Propiedades | |
---|---|
id |
string Es el ID de la recuperación en segundo plano. |
uploadTotal |
number Es la cantidad de bytes que se enviarán al servidor. |
uploaded |
number Es la cantidad de bytes que se enviaron correctamente. |
downloadTotal |
number El valor proporcionado cuando se registró la recuperación en segundo plano o cero. |
downloaded |
number Es la cantidad de bytes recibidos correctamente. Este valor puede disminuir. Por ejemplo, si se interrumpe la conexión y no se puede reanudar la descarga, en cuyo caso el navegador reinicia la recuperación de ese recurso desde cero. |
result |
Uno de los siguientes:
|
failureReason |
Uno de los siguientes:
|
recordsAvailable |
boolean ¿Se puede acceder a las solicitudes o respuestas subyacentes? Una vez que se establece en falso, no se pueden usar |
Métodos | |
abort() |
Devuelve Promise<boolean> para anular la recuperación en segundo plano. La promesa devuelta se resuelve con el valor verdadero si la recuperación se anuló correctamente. |
matchAll(request, opts) |
Devuelve Promise<Array<BackgroundFetchRecord>> Obtén las solicitudes y las respuestas. Los argumentos aquí son los mismos que los de la API de caché. Si se llama sin argumentos, se devuelve una promesa para todos los registros. Consulte la siguiente información para obtener más detalles. |
match(request, opts) |
Devuelve Promise<BackgroundFetchRecord> Como se indicó anteriormente, pero se resuelve con la primera coincidencia. |
Eventos | |
progress |
Se activa cuando cambia cualquiera de los valores de uploaded , downloaded , result o failureReason . |
Seguimiento del progreso
Esto se puede hacer a través del evento progress
. Recuerda que downloadTotal
es el valor que proporcionaste o 0
si no proporcionaste un 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}%`);
});
Cómo obtener las solicitudes y respuestas
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
es un BackgroundFetchRecord
y se ve de la siguiente manera:
Propiedades | |
---|---|
request |
Request Es la solicitud que se proporcionó. |
responseReady |
Promise<Response> La respuesta recuperada. La respuesta está detrás de una promesa porque es posible que aún no se haya recibido. La promesa se rechazará si falla la recuperación. |
Eventos de service worker
Eventos | |
---|---|
backgroundfetchsuccess |
Todo se recuperó correctamente. |
backgroundfetchfailure |
Se produjo un error en una o más recuperaciones. |
backgroundfetchabort |
Se produjo un error en una o más recuperaciones.
Esto solo es útil si deseas limpiar los datos relacionados. |
backgroundfetchclick |
El usuario hizo clic en la IU de progreso de descarga. |
Los objetos de eventos tienen lo siguiente:
Propiedades | |
---|---|
registration |
BackgroundFetchRegistration |
Métodos | |
updateUI({ title, icons }) |
Te permite cambiar el título o los íconos que configuraste inicialmente. Esto es opcional, pero te permite proporcionar más contexto si es necesario. Solo puedes hacerlo *una vez* durante los eventos backgroundfetchsuccess y backgroundfetchfailure . |
Reaccionar al éxito o al fracaso
Ya vimos el evento progress
, pero solo es útil mientras el usuario tiene una página abierta en tu sitio. El principal beneficio de la recuperación en segundo plano es que las cosas siguen funcionando después de que el usuario abandona la página o incluso cierra el navegador.
Si la recuperación en segundo plano se completa correctamente, tu service worker recibirá el evento backgroundfetchsuccess
y event.registration
será el registro de la recuperación en segundo plano.
Después de este evento, ya no se puede acceder a las solicitudes y respuestas recuperadas, por lo que, si quieres conservarlas, muévelas a algún lugar como la API de caché.
Al igual que con la mayoría de los eventos de Service Worker, usa event.waitUntil
para que el Service Worker sepa cuándo se completa el evento.
Por ejemplo, en tu 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!' });
}());
});
Es posible que el error se haya debido a un solo error 404, que tal vez no haya sido importante para ti, por lo que aún podría valer la pena copiar algunas respuestas en una caché como se indicó anteriormente.
Reacción al clic
Se puede hacer clic en la IU que muestra el progreso y el resultado de la descarga. El evento backgroundfetchclick
en el trabajador de servicio te permite reaccionar a esto. Como se indicó anteriormente, event.registration
será el registro de recuperación en segundo plano.
Lo más común que se hace con este evento es abrir una ventana:
addEventListener('backgroundfetchclick', (event) => {
const bgFetch = event.registration;
if (bgFetch.result === 'success') {
clients.openWindow('/latest-podcasts');
} else {
clients.openWindow('/download-progress');
}
});
Recursos adicionales
Corrección: En una versión anterior de este artículo, se hizo referencia de forma incorrecta a la Recuperación en segundo plano como un "estándar web". Actualmente, la API no se encuentra en la ruta de estándares. La especificación se puede encontrar en WICG como un borrador de informe del Grupo de la comunidad.