Arka Plan Getirme ile tanışın

Jake Archibald
Jake Archibald

2015'te, hizmet çalışanının kullanıcı bağlantı kurana kadar işi ertelemesine olanak tanıyan Arka Plan Senkronizasyonu'nu kullanıma sunduk. Bu sayede kullanıcılar mesaj yazıp gönder'i tıkladıktan sonra siteyi terk edebilir. Mesaj, ya hemen ya da bağlantı kurulduğunda gönderilir.

Bu özellik kullanışlı olsa da getirme işlemi süresince hizmet çalışanının etkin olması gerekir. Bu durum, mesaj gönderme gibi kısa süreli işlemler için sorun teşkil etmez. Ancak görev çok uzun sürerse tarayıcı, hizmet çalışanını sonlandırır. Aksi takdirde kullanıcının gizliliği ve pil ömrü risk altında olur.

Peki, film, podcast veya oyun seviyeleri gibi uzun sürebilecek bir şeyi indirmeniz gerekirse ne yaparsınız? Arka planda getirme bu amaçla kullanılır.

Arka planda getirme, Chrome 74'ten beri varsayılan olarak kullanılabilir.

İşlerin geleneksel durumunu ve arka planda getirme özelliğinin kullanımını gösteren iki dakikalık kısa bir demoyu aşağıda bulabilirsiniz:

İşleyiş şekli

Arka planda getirme işlemi şu şekilde çalışır:

  1. Tarayıcıya bir grup getirme işlemini arka planda gerçekleştirmesini söylersiniz.
  2. Tarayıcı bu öğeleri getirir ve kullanıcının ilerleme durumunu gösterir.
  3. Getirme işlemi tamamlandığında veya başarısız olduğunda tarayıcı, hizmet çalışanınızı açar ve ne olduğunu bildirmek için bir etkinlik tetikler. Yanıtlarla ilgili ne yapacağınıza (varsa) bu aşamada karar verirsiniz.

Kullanıcı, 1. adımdan sonra sitenizin sayfalarını kapatırsa indirme işlemi devam eder. Getirme işlemi çok görünür ve kolayca iptal edilebilir olduğundan, çok uzun süren bir arka plan senkronizasyonu göreviyle ilgili gizlilik endişesi yoktur. Service worker sürekli çalışmadığı için arka planda Bitcoin madenciliği gibi sistemin kötüye kullanılması söz konusu değildir.

Bazı platformlarda (ör. Android) tarayıcı, getirme işlemini işletim sistemine devredebileceği için 1. adımdan sonra kapanabilir.

Kullanıcı, indirme işlemini internet bağlantısı yokken başlatırsa veya indirme sırasında internet bağlantısı kesilirse arka planda getirme işlemi duraklatılır ve daha sonra devam ettirilir.

API

Özellik algılama

Her yeni özellik gibi, tarayıcının bu özelliği destekleyip desteklemediğini de tespit etmeniz gerekir. Arka planda getirme için şu kadar basittir:

if ('BackgroundFetchManager' in self) {
  // This browser supports Background Fetch!
}

Arka planda getirme işlemini başlatma

Ana API, Service Worker kaydına bağlıdır. Bu nedenle, önce bir Service Worker kaydettiğinizden emin olun. Ardından:

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 işlevi üç bağımsız değişken alır:

Parametreler
id string
, bu arka plan getirme işlemini benzersiz bir şekilde tanımlar.

Kimlik mevcut bir arka plan getirme işlemiyle eşleşirse backgroundFetch.fetch reddeder.

requests Array<Request|string>
Getirilecek öğeler. Dizeler URL olarak değerlendirilir ve new Request(theString) aracılığıyla Request'ye dönüştürülür.

Kaynaklar CORS aracılığıyla izin verdiği sürece diğer kaynaklardan öğe getirebilirsiniz.

Not: Chrome şu anda CORS ön kontrolü gerektiren istekleri desteklememektedir.

options Aşağıdakileri içerebilen bir nesne:
options.title string
Tarayıcının ilerleme durumuyla birlikte göstereceği başlık.
options.icons Array<IconDefinition>
"src", "size" ve "type" özelliklerine sahip bir nesne dizisi.
options.downloadTotal number
Yanıt gövdelerinin toplam boyutu (gzip sıkıştırması kaldırıldıktan sonra).

Bu isteğe bağlı olsa da kesinlikle sağlamanız önerilir. İndirmenin boyutunu kullanıcıya bildirmek ve ilerleme durumu bilgileri sağlamak için kullanılır. Bu bilgiyi sağlamazsanız tarayıcı, kullanıcılara boyutun bilinmediğini bildirir. Bu durumda kullanıcıların indirme işlemini iptal etme olasılığı daha yüksek olabilir.

Arka planda getirme indirme sayısı burada verilen sayıyı aşarsa işlem iptal edilir. İndirme boyutu downloadTotal değerinden küçükse sorun olmaz. Bu nedenle, toplam indirme boyutunun ne olacağından emin değilseniz ihtiyatlı davranmanız önerilir.

backgroundFetch.fetch, BackgroundFetchRegistration ile çözülen bir söz döndürür. Bu konunun ayrıntılarını daha sonra ele alacağım. Kullanıcı indirmeleri devre dışı bıraktıysa veya sağlanan parametrelerden biri geçersizse söz reddedilir.

Tek bir arka plan getirme işlemi için birçok istek göndermek, kullanıcıya mantıksal olarak tek bir şey gibi görünen öğeleri birleştirmenize olanak tanır. Örneğin, bir film binlerce kaynağa bölünebilir (MPEG-DASH'te yaygın bir durumdur) ve resim gibi ek kaynaklarla birlikte gelebilir. Bir oyunun seviyesi birçok JavaScript, resim ve ses kaynağına yayılabilir. Ancak kullanıcı için bu sadece "film" veya "seviye"dir.

Mevcut bir arka planda getirme işlemini alma

Mevcut bir arka plan getirme işlemini şu şekilde alabilirsiniz:

navigator.serviceWorker.ready.then(async (swReg) => {
  const bgFetch = await swReg.backgroundFetch.get('my-fetch');
});

…istediğiniz arka planda getirme işleminin id değerini ileterek. get, bu kimliğe sahip etkin bir arka plan getirme işlemi yoksa undefined değerini döndürür.

Arka planda getirme işlemi, kaydedildiği andan itibaren başarılı olana, başarısız olana veya iptal edilene kadar "etkin" olarak kabul edilir.

getIds kullanarak etkin arka plan getirme işlemlerinin listesini alabilirsiniz:

navigator.serviceWorker.ready.then(async (swReg) => {
  const ids = await swReg.backgroundFetch.getIds();
});

Arka planda getirme kayıtları

Bir BackgroundFetchRegistration (yukarıdaki örneklerde bgFetch) şunları içerir:

Özellikler
id string
Arka planda getirme işleminin kimliği.
uploadTotal number
Sunucuya gönderilecek bayt sayısı.
uploaded number
Başarıyla gönderilen bayt sayısı.
downloadTotal number
Arka planda getirme kaydedildiğinde sağlanan değer veya sıfır.
downloaded number
Başarıyla alınan bayt sayısı.

Bu değer düşebilir. Örneğin, bağlantı kesilirse ve indirme işlemine devam edilemezse tarayıcı, söz konusu kaynağın getirme işlemini baştan başlatır.

result

Şunlardan biri:

  • "" - Arka planda getirme işlemi etkin olduğundan henüz sonuç yok.
  • "success" - Arka planda getirme işlemi başarılı oldu.
  • "failure" - Arka planda getirme işlemi başarısız oldu. Bu değer yalnızca arka planda getirme işlemi tamamen başarısız olduğunda (ör. tarayıcı yeniden deneme/devam ettirme işlemi yapamadığında) görünür.
failureReason

Şunlardan biri:

  • "" - Arka planda getirme başarısız olmadı.
  • "aborted": Arka planda getirme işlemi kullanıcı tarafından iptal edildi veya abort() çağrıldı.
  • "bad-status": Yanıtlardan birinin durumu "not-ok" (ör. 404) idi.
  • "fetch-error" - Getirme işlemlerinden biri başka bir nedenle (ör. CORS, MIX, geçersiz kısmi yanıt veya yeniden denenemeyen bir getirme işlemi için genel ağ hatası) başarısız oldu.
  • "quota-exceeded" - Arka planda getirme işlemi sırasında depolama alanı kotasına ulaşıldı.
  • "download-total-exceeded" - Belirtilen "downloadTotal" değeri aşıldı.
recordsAvailable boolean
Temel istekler/yanıtlar erişilebilir mi?

Bu değer yanlış olduğunda match ve matchAll kullanılamaz.

Yöntemler
abort() Promise<boolean>
Arka planda getirme işlemini durdurur.

Döndürülen söz, getirme işlemi başarıyla iptal edildiyse true ile çözümlenir.

matchAll(request, opts) Promise<Array<BackgroundFetchRecord>>
İstekleri ve yanıtları alın.

Buradaki bağımsız değişkenler önbellek API'si ile aynıdır. Bağımsız değişken olmadan yapılan çağrı, tüm kayıtlar için bir söz döndürür.

Daha ayrıntılı bilgi edinmek için aşağıdaki bölümü inceleyin.

match(request, opts) Döndürür Promise<BackgroundFetchRecord>
Yukarıdakiyle aynıdır ancak ilk eşleşmeyle çözülür.
Etkinlikler
progress uploaded, downloaded, result veya failureReason değerlerinden herhangi biri değiştiğinde tetiklenir.

İlerleme durumunu izleme

Bu işlem, progress etkinliği aracılığıyla yapılabilir. downloadTotal değerinin, sağladığınız değer veya değer sağlamadıysanız 0 olduğunu unutmayın.

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}%`);
});

İstekleri ve yanıtları alma

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, BackgroundFetchRecord ve şu şekilde görünüyor:

Özellikler
request Request
Sağlanan istek.
responseReady Promise<Response>
Getirilen yanıt.

Yanıt henüz alınmamış olabileceği için bir sözün arkasında kalıyor. Getirme işlemi başarısız olursa söz reddedilir.

Hizmet çalışanı etkinlikleri

Etkinlikler
backgroundfetchsuccess Her şey başarıyla getirildi.
backgroundfetchfailure Getirme işlemlerinden biri veya daha fazlası başarısız oldu.
backgroundfetchabort Bir veya daha fazla getirme işlemi başarısız oldu.

Bu özellik yalnızca ilgili verilerde temizleme işlemi yapmak istediğinizde kullanışlıdır.

backgroundfetchclick Kullanıcı, indirme ilerleme durumu kullanıcı arayüzünü tıkladı.

Etkinlik nesneleri şunları içerir:

Özellikler
registration BackgroundFetchRegistration
Yöntemler
updateUI({ title, icons }) Başlangıçta ayarladığınız başlığı/simgeleri değiştirmenize olanak tanır. Bu isteğe bağlıdır ancak gerekirse daha fazla bağlam bilgisi sağlamanıza olanak tanır. Bu işlemi yalnızca backgroundfetchsuccess ve backgroundfetchfailure etkinlikleri sırasında *bir kez* yapabilirsiniz.

Başarıya/başarısızlığa tepki verme

progress etkinliğini daha önce görmüştük ancak bu etkinlik yalnızca kullanıcı sitenizde bir sayfa açıkken yararlıdır. Arka planda getirme işleminin temel avantajı, kullanıcı sayfadan ayrıldıktan veya tarayıcıyı kapattıktan sonra bile işlemlerin devam etmesidir.

Arka planda getirme işlemi başarıyla tamamlanırsa hizmet çalışanınız backgroundfetchsuccess etkinliğini alır ve event.registration, arka planda getirme kaydı olur.

Bu etkinlikten sonra getirilen istek ve yanıtlara artık erişilemez. Bu nedenle, bunları saklamak istiyorsanız önbellek API'si gibi bir yere taşıyın.

Çoğu hizmet çalışanı etkinliğinde olduğu gibi, hizmet çalışanının etkinliğin ne zaman tamamlandığını bilmesi için event.waitUntil kullanın.

Örneğin, service worker'ınızda:

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!' });
  }());
});

Başarısızlık, sizin için önemli olmayabilecek tek bir 404 hatasından kaynaklanmış olabilir. Bu nedenle, bazı yanıtları yukarıdaki gibi bir önbelleğe kopyalamak yine de faydalı olabilir.

Tıklamaya tepki verme

İndirme ilerleme durumunu ve sonucunu gösteren kullanıcı arayüzü tıklanabilir. Hizmet çalışanındaki backgroundfetchclick etkinliği, bu duruma tepki vermenizi sağlar. Yukarıda belirtildiği gibi event.registration, arka planda getirme kaydı olacaktır.

Bu etkinlikte yaygın olarak yapılan işlem bir pencere açmaktır:

addEventListener('backgroundfetchclick', (event) => {
  const bgFetch = event.registration;

  if (bgFetch.result === 'success') {
    clients.openWindow('/latest-podcasts');
  } else {
    clients.openWindow('/download-progress');
  }
});

Ek kaynaklar

Düzeltme: Bu makalenin önceki bir sürümünde, Arka Planda Getirme yanlış bir şekilde "web standardı" olarak adlandırılıyordu. API şu anda standartlar yolunda değildir. Spesifikasyon, WICG'de Topluluk Grubu Raporu Taslağı olarak bulunabilir.