Arka Plan Getirme ile tanışın

Jake Archibald
Jake Archibald

2015'te Arka Plan Senkronizasyonu'nu kullanıma sunduk. Bu sayede hizmet çalışanı, bağlantı kurana kadar çalışmayı erteleyebilir. Bu, kullanıcının bir mesaj yazıp Gönder'e basabileceği ve mesajın şimdi ya da bağlantısı olduğunda gönderileceğini bilerek siteden ayrılabileceği anlamına gelir.

Bu faydalı bir özelliktir ancak hizmet çalışanının getirme işlemi süresince aktif olmasını gerektirir. Mesaj göndermek gibi kısa süreli işlemler için bu bir sorun değildir ancak görev çok uzun sürerse tarayıcı hizmet çalışanını öldürür. Aksi takdirde kullanıcının gizliliği ve pili için bir risk söz konusudur.

Peki, film, podcast veya bir oyun seviyesi gibi uzun sürebilecek bir içeriği indirmeniz gerekiyorsa ne olur? Arka Planda Getirme'nin amacı budur.

Arka Planda Getirme, Chrome 74'ten itibaren varsayılan olarak kullanılabilmektedir.

Aşağıda, Arka Planda Getirme ile ilgili geleneksel işlemin nasıl yapıldığını gösteren iki dakikalık kısa bir demo sunulmuştur:

Demoyu kendiniz deneyin ve koda göz atın.

İşleyiş şekli

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

  1. Tarayıcıya, arka planda bir grup getirme işlemi yapmasını söylersiniz.
  2. Tarayıcı bu bilgileri getirir ve kullanıcıya 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 size ne olduğunu bildirmek için bir etkinlik tetikler. Burada yanıtlarla ilgili ne yapacağınıza karar verirsiniz.

Kullanıcı 1. adımdan sonra sitenizin sayfalarını kapatırsa sorun değil, indirme işlemi devam eder. Getirme işlemi oldukça görünür ve kolayca iptal edilebilir olduğundan, arka plandaki senkronizasyon görevinin çok uzun olması gibi bir gizlilik sorunu yoktur. Service Worker sürekli çalışmadığı için arka planda bitcoin madenciliği yapmak gibi sistemi kötüye kullanma riski yoktur.

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

Kullanıcı indirme işlemini çevrimdışıyken başlatır veya indirme sırasında çevrimdışı olursa arka planda getirme duraklatılır ve daha sonra devam ettirilir.

API

Özellik algılama

Her yeni özellikte olduğu gibi, tarayıcının bu özelliği destekleyip desteklemediğini tespit etmek istersiniz. Arka Plan Getirme için yapmanız gereken basit işlem:

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

Arka planda getirme işlemi başlatma

Ana API, hizmet çalışanı kaydında takılır. Bu nedenle, önce bir hizmet çalışanı kaydettirdiğ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 üç bağımsız değişken alır:

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

backgroundFetch.fetch, kimliğin mevcut bir arka plan getirme işlemiyle eşleşmesi durumunda reddeder.

requests Array<Request|string>
Getirmeniz gereken şeyler. Dizeler, URL olarak işlenecek ve new Request(theString) aracılığıyla Request biçimine dönüştürülecek.

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

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

options Şunları içerebilecek bir nesne:
options.title string
İlerlemeyle birlikte gösterilecek tarayıcı başlığı.
options.icons Array<IconDefinition>
"src", "size" ve "type" içeren nesne dizisi.
options.downloadTotal number
Yanıt gövdelerinin toplam boyutu (gzip çıkarıldıktan sonra).

İsteğe bağlı olsa da bu bilgiyi sağlamanız önemle tavsiye edilir. Bu numara, kullanıcıya indirmenin ne kadar büyük olduğunu bildirmek ve ilerleme durumu bilgilerini sağlamak için kullanılır. Bu bilgiyi sağlamazsanız tarayıcı, kullanıcıya boyutun bilinmediğini bildirir ve bunun sonucunda kullanıcını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. İndirilen dosya downloadTotal boyutundan küçükse herhangi bir sorun yoktur. Bu yüzden, toplam indirmenin ne kadar olacağından emin değilseniz tedbiri elden bırakmamanız önerilir.

backgroundFetch.fetch, BackgroundFetchRegistration ile sonuçlanacak bir söz döndürür. Bununla ilgili ayrıntıları 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 çok sayıda istek sağlamak, kullanıcı için mantıksal olarak tek şey olan öğeleri birleştirmenize olanak tanır. Örneğin, bir film binlerce kaynağa bölünebilir (genellikle MPEG-DASH ile) ve resimler gibi ek kaynaklar içerebilir. Bir oyun seviyesi birçok JavaScript, resim ve ses kaynağına yayılabilir. Ancak kullanıcı gözünde yalnızca "film" veya "seviye" olarak düşünülebilir.

Mevcut bir arka plan getirme işlemi alınıyor

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

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

...istediğiniz arka plan getirme işleminin id değerini ileterek. get, bu kimlikle 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 planda getirme işlemlerinin tümünün listesini alabilirsiniz:

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

Arka planda getirme kayıtları

BackgroundFetchRegistration (yukarıdaki örneklerde bgFetch) aşağıdakilere sahiptir:

Ö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 azalabilir. Örneğin, bağlantı kesilirse ve indirme işlemi devam ettirilemezse tarayıcı bu kaynağı getirme işlemini en baştan başlatır.

result

Şunlardan biri:

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

Şunlardan biri:

  • "" - Arka planda getirme başarısız oldu.
  • "aborted" – Arka plan getirme işlemi kullanıcı tarafından iptal edildi veya abort() çağrıldı.
  • "bad-status" - Yanıtlardan birinin "uygun değil" durumu (ör. 404) vardı.
  • "fetch-error": Getirme işlemlerinden biri başka bir nedenden dolayı başarısız oldu (ör. CORS, MIX, geçersiz kısmi yanıt veya yeniden denenmeyen bir getirme işlemi için genel ağ hatası).
  • "quota-exceeded": Arka planda getirme işlemi sırasında depolama alanı kotasına ulaşıldı.
  • "download-total-exceeded" - Sağlanan "downloadTotal" (indirilen toplam) aşıldı.
recordsAvailable boolean
Temel isteklere/yanıtlara erişilebilir mi?

Yanlış olduğunda match ve matchAll kullanılamaz.

Yöntemler
abort() Promise<boolean> değerini döndürür
Arka plan getirme işlemini iptal eder.

Döndürülen vaat, getirme işlemi başarıyla iptal edilirse true olarak çözümlenir.

matchAll(request, opts) Promise<Array<BackgroundFetchRecord>> ifadesini döndürür.
İstekleri ve yanıtları al.

Buradaki bağımsız değişkenler cache API ile aynıdır. Bağımsız değişken olmadan çağrı yapılması 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) Yukarıdaki gibi Promise<BackgroundFetchRecord>
değerini döndürür ancak ilk eşleşmeyle çözümlenir.
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 olduğunu veya bir değer girmediyseniz 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}%`);
});

İstek 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 bir BackgroundFetchRecord ve aşağıdaki gibi görünüyor:

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

Yanıt, henüz alınmamış olabileceği için bir vaadin arkasındadır. Getirme başarısız olursa söz reddedilir.

Hizmet çalışanı etkinlikleri

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

Bu, yalnızca ilgili verileri temizlemek istiyorsanız gerçekten yararlı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 sağlamanıza olanak tanır. Bu işlemi backgroundfetchsuccess ve backgroundfetchfailure etkinlikleri sırasında yalnızca *bir kez* yapabilirsiniz.

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

progress etkinliğini daha önce görmüştük. Ancak bu, yalnızca kullanıcının sitenizi açmış bir sayfası olduğunda yararlı olur. Arka planda getirmenin temel avantajı, kullanıcı sayfadan ayrıldıktan veya hatta tarayıcıyı kapattıktan sonra da çalışmaya devam etmesidir.

Arka planda getirme 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 istekler ve yanıtlara artık erişilemez. Bunları saklamak istiyorsanız cache API 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, hizmet çalışanı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 olmayan tek bir 404 hatasına yol açmış olabilir. Bu nedenle bazı yanıtları yukarıdaki gibi önbelleğe kopyalamak iyi bir fikir olabilir.

Tıklamaya tepki verme

İndirme işleminin ilerleme durumunu ve sonucu gösteren kullanıcı arayüzü tıklanabilir. Service Worker'daki backgroundfetchclick etkinliği bu duruma tepki vermenizi sağlar. Yukarıdaki event.registration, arka planda getirme kaydı olacaktır.

Bu etkinlikle ilgili genel işlem 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 Plan Getirme'den yanlışlıkla "web standardı" olarak bahsediliyordu. Bu API şu anda standartlar yolunda yer almıyor. İlgili spesifikasyonu WICG'de Taslak Topluluk Grubu Raporu olarak bulabilirsiniz.