Service Workers ile Offline-First Yaklaşımı

Service Workers ile Offline-First Yaklaşımı

Review of: Service Worker

Reviewed by:
Rating:
5
On 03/08/2018
Last modified:03/20/2018

Summary:

Dünya üzerinde en fazla kullanılan dillerden olan Javascript alanında her geçen yıl yeni gelişmeler yaşanıyor.

Bu gelişmeler özellikle EGMAScript ile birlikte oluyor. EGMAScript bir nevi javascript standardlarının belirlendiği bir standard script diyebiliriz.

ES2015(ES5) ve ES2016(ES6) ile birlikte Javascript dünyasında çok önemli güncellemelerin duyuruları yapıldı. Javascript her geçen gün güçlenmeye ve yaygınlaşmaya devam ediyor.

Gittikçe popüler olmaya başlayan diğer bir kavram ise Service Worker kavramıdır.

En basit haliyle anlatmam gerekirse sitenize biraz daha dinamiklik katan ve çevrimdışı beceriler ekleyebilmenize olanak sağlayan bir yapı diyebiliriz.

Daha fazla bilgi için Service Workers API dokümantasyonuna bakabilirsiniz.

Service Workers yolun başında olduğu için henüz bütün tarayıcılar tarafından desteklenmiyor fakat bu demek değil ki bu yapıyı kullanmayalım.

Tarayıcı uyumluluğu tablosu için de buraya bakabilirsiniz.

Service Worker Kayıt Etme

Bir web uygulaması için birden fazla Service Worker olabilir fakat bu yazımda bir tane varmış kabul edip örnekleri ona göre vereceğim.

Öncelikle web uygulamamızda Service Worker yapısını kullanabilmemiz için kayıt ettirmemiz gerekiyor.

Service Worker Kayıt

/**
* Service Worker Registration
*/
// if browser doesn't support. don't bother to continue.
if(navigator.serviceWorker){
    navigator.serviceWorker.register('/sw.js', {scope: './'})
    .then((reg) => {
        console.log("Service worker has been successfully registered.");      
    }).catch((err) => {
        console.log("error " , err);      
    });
}

if(navigator.serviceWorker) kontrolüyle destekleyen tarayıcılarda işlem yapmasını sağlamış olduk.

Kayıt esnasında register fonksiyonuna iki tane parametre gönderdik. Bunlardan ilki sw.js ikincisi ise ./ oldu.

sw.js ile kayıt esnasında bu kayıt işlemindeki service worker yapısının olduğu dosyanın yolunu belirtiyoruz.

Service Worker kayıt işlemi esnasında belirttiğimiz scope parametresi, hangi alanlarda geçerli olduğunu belirtiyor. ./ şeklinde belirterek, bütün websitesinde geçerli olmasını sağladık.

Önemli Not : Örnek olarak vermek gerekirse; /images ile /images/ aynı scope değildir.

Eğer web uygulamanızda birden fazla Service Worker kullanmayacaksanız scope belirtmenize gerek yok.

Evet, Service Worker yapımızı başarılı bir şekilde kayıt ettik. Sayfayı yenileyelim ve ne olduğuna bakalım.

Service Worker Kayıt

Service Worker yapımızı uygulamamıza kayıt ettik fakat şimdilik hiçbir şey yapmıyor. Şimdi Service Worker yapımızı kullanalım.

Service Worker Yaşam Döngüsü

Service Worker yapısını iyi bir şekilde kullanabilmemiz için yaşam döngüsünü anlamamız gerekmektedir. Yaşam döngüsü, Service Worker yapısı ile çalışırken oldukça önemli bir hâle geliyor çünkü bu kısmı iyi anlarsak, Service Worker yapısını daha verimli kullanabiliriz.

Service Worker yapısı temelde iki ana aşamadan oluşuyor.

  1. Install
  2. Activate

Bu şekilde aşamalardan oluşmasının birkaç sebebi şunlardır :

  • Offline-first yaklaşımını sağlamak
  • Mevcut Service Worker yapısını bozmadan kayıt edilen yeni Service Worker’ın kendini hazırlaması.
  • Aynı scope içerisinde aynı Service Worker’ın çalıştığından emin olmak.
  • Aynı anda sitenin tek bir versiyonunun sunulduğundan emin olmak.

Haydi, Service Worker yapısını kurmaya başlayalım.

Öncelikle kayıt esnasında belirttiğimiz sw.js dosyayı oluşturalım.

//sw.js

/**
* Service Worker install
*/
self.addEventListener('fetch' , function(event) { 
    console.log(event.request);
});

Bu aşamada Service Worker yapımızın çalışıp çalışmadığını kontrol edebiliriz. Şimdi sayfayı yenileyelim.

Hiçbir şey göremediniz değil mi ?

Şimdi ise tekrar yenileyelim. Evet şimdi aşağıdaki resimde olduğu gibi istekleri görmeye başladınız değil mi ?

Service Worker Fetch

Peki neden sayfayı iki kere yenilememiz gerekti ?

Bu olayın sebebi Service Worker’ın yaşam döngüsü ile alakalı. Yukarıda bahsettiğim nedenden ötürü, uygulamanın tek bir versiyonunun çalıştığından emin olmak için böyle bir yaşam döngüsü mevcut. Yani, her şey geliştirilirken kullanıcı baz alınarak geliştirilmiş.

Service Worker yaşam döngüsü işin en karışık kısımlarından birisi, fakat bir kere anladınız mı gerisi çok basit.

İki refresh gerekmesinin sebebi ise, kayıt işlemi esnasında belirttiğimiz Service Worker’ın sayfadaki kontrolü eline almamasından kaynaklanıyor. Yani aslında ilk refresh ile Service Worker kayıt işlemi tamamlanıyor fakat sayfadaki kontrol Service Worker üzerinde olmuyor. Bu yüzden bir kere daha yeniliyoruz(veya başka bir sayfaya girebilirsiniz) ve Service Worker kontrolü ele alıyor.

Önemli Not : Mevcut Service Worker’ın yapısı hiç değişmemiş bile olsa(yorum satırı ekleyip deneyin), tarayıcı bunu Service Worker’ın yeni versiyonu olarak algılayacaktır.

Şimdi size bir şey daha göstermek istiyorum. Mevcut Service Worker(sw.js) yapımıza bir yorum satırı ekleyelim ve sayfayı yenileyelim

//sw.js

/**
* Service Worker install
*/
// ********* alpmusti.com **********
self.addEventListener('fetch' , function(event) { 
    console.log(event.request);
});

Service Worker Waiting

O da ne? #1 waiting to activate şeklinde yeni bir Service Worker sayfayı devralmayı bekliyor. Oysa ki sadece bir yorum satırı eklemiştik.

Biraz kafa karıştırıcı değil mi ?

Bunu kolaylaştırmak için Google Chrome‘un bize sunduğu bir seçenek mevcut. Geliştirici Konsolu > Application kısmına gidin ve Update on reload kısmını işaretleyin.

Bu seçenek sayfayı bir kere yenileseniz bile Service Worker yapısının kontrolü ele almasını sağlayacaktır. Böylelikle geliştirme yaparken sürekli Service Worker’ın devreye girmesini beklemeyeceğiz. Tek bir kere yenilememiz yeterli olacak.

Statik Cache Oluşturma

Evet, Service Worker yapısını anladık ve istekleri görmeye başladık. Fakat hâla Service Worker yapımız hiçbir şey yapmıyor.

Şimdi Install aşamasında, yani Service Worker yapısı yüklenirken sitemizin bazı kısımlarını önbelleğe almasını isteyeceğiz.

//sw.js
/**
* Service Worker install
*/
// ********* alpmusti.com **********

var cacheName = 'restaurant-reviews-v1';

self.addEventListener('install', function(event) {
  // event.waitUntil Delays the event until the Promise is resolved
  event.waitUntil(
    // Open the cache
    caches.open(cacheName).then(function(cache) {
    // Add all the default files to the cache
    return cache.addAll([
        '/',
        '/img/*.jpg',
        'restaurant.html',
        'index.html',
        'js/app.js',
        'js/main.js',
        'js/dbhelper.js',
        'data/restaurants.json',
        'js/restaurant_info.js',
        'css/styles.css',
        'https://cdnjs.cloudflare.com/ajax/libs/normalize/8.0.0/normalize.min.css',
        'https://fonts.googleapis.com/css?family=Roboto:300,400,500,700'
      ]).catch((error) => console.log("caches open : " ,error));
    })
  ); // end event.waitUntil
});

Bu aşamada Cache API ile sayfamızın statik kaynaklarını önbelleğe almış olduk.

Eğer her şeyi doğru yaptıysanız, aşağıdaki gibi bir çıktı görmeniz gerekiyor.

Service Worker Statik Cache

Önbellekteki Dosyaları Sunma

Evet buraya kadar birçok işlem gerçekleştirdik. İlk Offline-first deneyiminizi yaşamanıza çok az kaldı.

Şimdi önbelleğe aldığımız dosyaları kullanıcıya bir şekilde sunmamız gerekiyor. Bunu da daha önce gördüğünüz fetch event listener ile yapacağız.

/**
* Fetch Event Listener
*/
// *********** alpmusti.com *********
self.addEventListener('fetch', function(event){  
  event.respondWith(
    caches.open(cacheName).then(function(cache) {
      return cache.match(event.request).then(function (response) {
        return response || fetch(event.request).then(function(response) {
          cache.put(event.request, response.clone());
          return response;
        });
      });
    })
  );
});

event.respondWith() yapısı ile kullanıcıya cevap dönderme işlemini gerçekleştirmemiz gerekiyor. Bu cevap içerisinde eğer kullanıcının yaptığı istek bizim önbelleğimizde mevcut ise, ön bellek üzerinden sunuyoruz. Eğer kullanıcının istek yaptığı şey bizim önbelleğimizde yoksa ağ üzerinden istiyoruz. Sonrasında ağ üzerinden gelen cevabı da önbelleğimize alıyoruz ki bir sonraki sefer de kullanabilelim.

Önemli Not : response.clone() fonksiyonuna dikkat ediniz. Gelen cevabı önbelleğe alırken orijinal cevabın body kısmını sadece bir kere kullanabiliriz. Bu yüzden cevabın kopyasını önbelleğe alıyoruz.

Sonuç

Epey bir teknik terimden ve olaydan bahsettik.

Evet başardınız! Tebrikler, offline-first yaklaşımını web uygulamanıza dahil ettiniz.

Hep beraber bir Service Worker yapısını statik olarak hazırlanmış bir websitesine offline yetenekler ekleyerek sunduk. Kullanıcılar artık internet bağlantısı olmasa da web uygulamanızla etkileşime girebilecekler.

Tüm kaynak kodlarına github üzerinden aşağıdaki bağlantıdan ulaşabilirsiniz.

Kaynak kod

Son olarak, yazıyı beğendiyseniz paylaşmayı unutmayın. İyi kodlamalar.


Paylaş :

Full Stack Developer · Yazılım Tutkunu · Fikir, kod ve teknoloji Daha fazlası için hakkımda sayfasını ziyaret edebilirsiniz.



Bu yazı hakkındaki görüşünü benimle paylaşmaya ne dersin ?


Email adresiniz yayınlanmayacaktır.

Yorum yap butonuna
  bastıktan sonra yorumunuz gönderilecektir. Yorumunuz incelenip onaylandıktan sonra diğer ziyaretçilerimiz tarafından da görünecektir. Lütfen, yorum yaparken saygı çerçevesinde ve hakaret etmeden yorum yapmaya özen gösteriniz.

Bu yorumu göndererek bu uyarıları okuduğumu ve kabul ettiğimi onaylıyorum.

This site uses Akismet to reduce spam. Learn how your comment data is processed.