Hizmet çalışanlarını düşünürken nasıl düşünmelisiniz?
Hizmet çalışanları güçlüdür ve kesinlikle öğrenmeye değerdir. Kullanıcılarınıza yepyeni bir deneyim sunmanıza olanak tanırlar. Siteniz anında yüklenebilir. Çevrimdışı çalışabilir. Platforma özel bir uygulama olarak yüklenebilir ve her açıdan şık bir deneyim sunabilir ancak web'in erişimi ve özgürlüğünü de sunar.
Ancak hizmet işçileri, çoğu web geliştiricisinin alıştığı hiçbir şeye benzemez. Bu tür uygulamalarda öğrenme süreci oldukça uzundur ve dikkat etmeniz gereken bazı zorluklar vardır.
Google Developers ve ben kısa süre önce, Service Worker'ları anlamaya yönelik ücretsiz bir oyun olan Service Workies'te ortak çalışma yaptık. Şirketi oluştururken ve hizmet çalışanları ile çalışırken birkaç sorunla karşılaştım. En çok yardımcı olan şey, birkaç açıklayıcı metafor bulmaktı. Bu gönderide, bu zihinsel modelleri inceleyecek ve beyinlerimizi, hizmet çalışanlarını hem ustalıklı hem de harika kılan paradoksal özelliklere çevireceğiz.
Aynı ama farklı
Hizmet işleyicinizi kodlarken birçok şey tanıdık gelecektir. En sevdiğiniz yeni JavaScript dili özelliklerini kullanmaya başlayabilirsiniz. Kullanıcı arayüzü etkinliklerinde olduğu gibi yaşam döngüsü olaylarını dinlersiniz. Kontrol akışını, alıştığınız gibi promises ile yönetirsiniz.
Ancak diğer hizmet çalışanı davranışları kafanızın karışmasına neden oluyor. Özellikle sayfayı yenilediğinizde kod değişikliklerinizin uygulanmadığını gördüğünüzde.
Yeni bir katman
Normalde bir site oluştururken dikkate almanız gereken iki katman vardır: istemci ve sunucu. Service Worker, ortada bulunan yepyeni bir katmandır.
Hizmet çalışanınızı, sitenizin kullanıcınızın tarayıcısından yükleyebileceği bir tür tarayıcı uzantısı olarak düşünebilirsiniz. Hizmet çalışanı, yüklendikten sonra siteniz için tarayıcıya güçlü bir orta katman ekleyerek sitenizi geliştirir. Bu hizmet çalışanı katmanı, sitenizin gönderdiği tüm isteklere müdahale edip bunları işleyebilir.
Hizmet çalışanı katmanının, tarayıcı sekmesinden bağımsız kendi yaşam döngüsü vardır. Bir sunucuda dağıtılan kodun güncellenmesi için bir sayfanın yenilenmesini beklememeniz gibi, basit bir sayfa yenilemesi Service Worker'ı güncellemek için yeterli değildir. Her katmanın güncellemeyle ilgili kendine özgü kuralları vardır.
Service Workies oyununda, servis çalışanı yaşam döngüsünün birçok ayrıntısını ele alıyoruz ve bu konuda bolca alıştırma yapmanızı sağlıyoruz.
Güçlü ancak sınırlı
Sitenizde bir hizmet çalışanının olması size inanılmaz avantajlar sağlar. Siteniz:
- Kullanıcı çevrimdışıyken bile sorunsuz çalışır.
- Önbelleğe alma yoluyla büyük performans iyileştirmeleri elde edin
- Push bildirimleri kullanın
- PWA olarak yüklü olmalıdır
Hizmet işçileri, tasarım gereği sınırlı bir işleve sahiptir. Eşzamanlı olarak veya sitenizle aynı ileti dizisinde herhangi bir işlem yapamaz. Bu nedenle aşağıdakilere erişemezsiniz:
- localStorage
- DOM
- pencere
Neyse ki sayfanızın hizmet işçisiyle iletişim kurmasının birkaç yolu vardır. Doğrudan postMessage
, bire bir Mesaj Kanalları ve bire çok Yayın Kanalları bunlardan bazılarıdır.
Uzun ömürlü ancak kısa ömürlü
Etkin bir hizmet çalışanı, kullanıcı sitenizden ayrıldıktan veya sekmeyi kapattıktan sonra bile çalışmaya devam eder. Tarayıcı, kullanıcı sitenize tekrar geldiğinde hazır olması için bu hizmet çalışanını saklar. İlk istek gönderilmeden önce hizmet çalışanı, isteği durdurup sayfanın kontrolünü ele alma şansı elde eder. Bu sayede site çevrimdışı çalışabilir. Hizmet çalışanı, kullanıcının internet bağlantısı olmasa bile sayfanın önbelleğe alınmış bir sürümünü sunabilir.
Service Workies'de bu kavramı, istekleri yakalayıp işleyen Kolohe (sevimli bir hizmet çalışanı) ile görselleştiriyoruz.
Durduruldu
Hizmet çalışanları ölümsüz gibi görünse de neredeyse her zaman durdurulabilir. Tarayıcı, şu anda hiçbir şey yapmayan bir hizmet çalışanı için kaynak israf etmek istemez. Durdurulmak feshetmekle aynı şey değildir. Service Worker'ın yüklü ve etkin durumda olduğu anlamına gelir. Sadece uyku moduna geçirilir. Bir sonraki sefere ihtiyaç duyulduğunda (ör. bir isteği işlemek için) tarayıcı bu işlemi tekrar başlatır.
waitUntil
Sürekli olarak uykuya geçirilme olasılığı nedeniyle, hizmet çalışanınızın önemli bir şey yaptığında ve uykuya dalmak istemediğinde bunu tarayıcıya bildirmenin bir yoluna ihtiyacı vardır. Bu noktada event.waitUntil()
devreye girer. Bu yöntem, kullanıldığı yaşam döngüsünü uzatarak hem durdurulmasını hem de hazır olana kadar yaşam döngüsünün bir sonraki aşamasına geçmesini engeller. Bu sayede önbellekleri ayarlayabilir, ağdan kaynak getirebilir vb. işlemleri yapabiliriz.
Bu örnekte tarayıcıya, assets
önbelleği oluşturulup bir kılıç resmiyle doldurulana kadar hizmet işleyicimizin yükleme işleminin tamamlanmadığı bildirilmektedir:
self.addEventListener("install", event => {
event.waitUntil(
caches.open("assets").then(cache => {
return cache.addAll(["/weapons/sword/blade.png"]);
})
);
});
Global duruma dikkat edin
Bu başlatma/durdurma işlemi gerçekleştiğinde hizmet çalışanının genel kapsamı sıfırlanır. Bu nedenle, hizmet çalışanınızda hiçbir genel durumu kullanmamaya dikkat edin. Aksi takdirde, bir sonraki uyandığında ve beklediğinden farklı bir durumunda olduğunda üzülürsünüz.
Genel durumu kullanan şu örneği düşünün:
const favoriteNumber = Math.random();
let hasHandledARequest = false;
self.addEventListener("fetch", event => {
console.log(favoriteNumber);
console.log(hasHandledARequest);
hasHandledARequest = true;
});
Bu hizmet çalışanı, her istek için bir sayı (ör. 0.13981866382421893
) günlüğe kaydeder. hasHandledARequest
değişkeni de true
olarak değişir. Şimdi hizmet çalışanı bir süre boşta kaldığından tarayıcı bunu durdurur. Bir sonraki istek geldiğinde hizmet çalışanına tekrar ihtiyaç duyulur ve tarayıcı onu uyandırır. Komut dosyası yeniden değerlendirilir. Şimdi hasHandledARequest
değeri false
olarak sıfırlandı ve favoriteNumber
tamamen farklı bir değer (0.5907281835659033
).
Bir hizmet çalışanında depolanan duruma güvenemezsiniz. Ayrıca, Mesaj Kanalları gibi öğelerin örneklerinin oluşturulması hatalara neden olabilir: Hizmet çalışanı her durduğunda/başladığında yepyeni bir örnek alırsınız.
Service Workies bölümü 3'te, durdurulan hizmet çalışanımızın uyanılmasını beklerken tüm renklerinin kaybolduğunu görselleştiriyoruz.
Birlikte ama ayrı
Sayfanız aynı anda yalnızca bir hizmet çalışanı tarafından kontrol edilebilir. Ancak aynı anda iki hizmet çalışanı yüklenebilir. Service Worker kodunuzda değişiklik yapıp sayfayı yenilediğinizde hizmet çalışanınızı hiç düzenlemiş olmazsınız. Hizmet çalışanları sabit olur. Bunun yerine yeni bir tane oluşturuyorsunuz. Bu yeni hizmet çalışanı (SW2 olarak adlandıralım) yüklenir ancak henüz etkinleştirilmez. Mevcut hizmet çalışanının (SW1) sona ermesini (kullanıcınız sitenizden ayrıldığında) beklemesi gerekir.
Başka bir hizmet çalışanının önbelleğini bozma
SW2, yükleme sırasında genellikle önbellekleri oluşturup doldurarak bazı ayarları yapabilir. Ancak uyarı: Bu yeni Service Worker, mevcut Service Worker'ın erişebildiği her şeye erişebilir. Dikkatli olmazsanız bekleyen yeni hizmet çalışanınız, mevcut hizmet çalışanınız için işleri gerçekten alt üst edebilir. Size sorun çıkarabilecek bazı örnekler:
- SW2, SW1'in etkin olarak kullandığı bir önbelleği silebilir.
- SW2, SW1'in kullandığı bir önbelleğin içeriğini düzenleyebilir ve bu da SW1'in sayfanın beklemediği öğelerle yanıt vermesine neden olabilir.
skipWaiting işlevini atlama
Hizmet çalışanları, yükleme işlemi tamamlanır tamamlanmaz sayfanın kontrolünü ele almak için riskli skipWaiting()
yöntemini de kullanabilir. Hatalı bir servis çalışanını değiştirmeye kasten değilseniz bu genellikle kötü bir fikirdir. Yeni hizmet çalışanı, mevcut sayfanın beklemediği güncellenmiş kaynakları kullanıyor olabilir. Bu da hatalara ve böceklere neden olur.
Temiz bir başlangıç yapın
Hizmet çalışanlarınızın birbirini engellemesini önlemek için farklı önbellekler kullanmasını sağlayın. Bunu yapmanın en kolay yolu, kullandıkları önbellek adlarını sürümlere ayırmaktır.
const version = 1;
const assetCacheName = `assets-${version}`;
self.addEventListener("install", event => {
caches.open(assetCacheName).then(cache => {
// confidently do stuff with your very own cache
});
});
Yeni bir hizmet çalışanı dağıttığınızda version
öğesini, önceki hizmet çalışanından tamamen ayrı bir önbellek ile ihtiyacını yapması için dokundurursunuz.
Son temizlik
Service Worker'ınız activated
durumuna ulaştığında artık bu çalışanın devralındığını ve önceki hizmet çalışanının yedeklendiğini anlarsınız. Bu noktada, eski hizmet çalışanının ardından yer açılması önemlidir. Bu, kullanıcılarınızın önbellek depolama alanı sınırlarını gözetmekle kalmaz, aynı zamanda istenmeyen hataları da önleyebilir.
caches.match()
yöntemi, eşleşmenin bulunduğu herhangi bir önbellekten öğe almak için sık kullanılan bir kısayoldur. Ancak önbellekleri, oluşturuldukları sırayla iterasyon yapar. app.js
komut dosyası dosyasının iki farklı önbellekte (assets-1
ve assets-2
) iki sürümü olduğunu varsayalım. Sayfanız, assets-2
içinde depolanan daha yeni komut dosyasını bekliyor. Ancak eski önbelleği silmediyseniz caches.match('app.js')
, assets-1
'ten eskisini döndürür ve büyük olasılıkla sitenizi bozar.
Önceki hizmet işçilerinin ardından temizlik yapmak için tek yapmanız gereken, yeni hizmet işçisinin ihtiyaç duymadığı tüm önbellekleri silmektir:
const version = 2;
const assetCacheName = `assets-${version}`;
self.addEventListener("activate", event => {
event.waitUntil(
caches.keys().then(cacheNames => {
return Promise.all(
cacheNames.map(cacheName => {
if (cacheName !== assetCacheName){
return caches.delete(cacheName);
}
});
);
});
);
});
Hizmet çalışanlarınızın birbirini ezmesini önlemek biraz çalışma ve disiplin gerektirir ancak buna değer.
Hizmet çalışanı bakış açısı
Hizmet çalışanlarını düşünürken doğru zihniyete sahip olmak, kendi çalışanlarınızı güvenle oluşturmanıza yardımcı olur. Bu özellikleri kavradıktan sonra kullanıcılarınız için mükemmel deneyimler oluşturabileceksiniz.
Tüm bunları oyun oynayarak öğrenmek istiyorsanız şanslısınız. Çevrimdışı canavarları öldürmek için servis çalışanının yollarını öğreneceğiniz Service Workies oyununu oynayın.