Bazı durumlarda, bir web uygulamasının sayfa ve Service Worker arasında iki yönlü bir iletişim kanalı oluşturması gerekebilir.
Örneğin, bir podcast PWA'da, kullanıcının çevrimdışı tüketim için bölümleri indirmesini sağlayan bir özellik oluşturulabilir ve hizmet çalışanı sayfayı ilerleme durumu hakkında düzenli olarak bilgilendirebilir. Böylece ana iş parçacığı kullanıcı arayüzünü güncelleyebilir.
Bu kılavuzda farklı API'leri, Workbox kitaplığını ve bazı ileri düzey durumları keşfederek Pencere ve hizmet çalışanı bağlamı arasında iki yönlü iletişim kurmanın farklı yollarını keşfedeceğiz.
Workbox'ı kullanma
workbox-window
, Workbox kitaplığının pencere bağlamında çalışması amaçlanan bir dizi modüldür. Workbox
sınıfı, örneğin kayıtlı hizmet çalışanına mesaj göndermek ve yanıt beklemek için bir messageSW()
yöntemi sağlar.
Aşağıdaki sayfa kodu yeni bir Workbox
örneği oluşturur ve hizmet çalışanına, sürümünü alması için bir mesaj gönderir:
const wb = new Workbox('/sw.js');
wb.register();
const swVersion = await wb.messageSW({type: 'GET_VERSION'});
console.log('Service Worker version:', swVersion);
Service Worker diğer tarafta bir mesaj dinleyici uygular ve kayıtlı hizmet çalışanına yanıt verir:
const SW_VERSION = '1.0.0';
self.addEventListener('message', (event) => {
if (event.data.type === 'GET_VERSION') {
event.ports[0].postMessage(SW_VERSION);
}
});
Kitaplıkta, bir sonraki bölümde inceleyeceğimiz bir tarayıcı API'si kullanılır: Message Channel, ancak bu API'nin sahip olduğu geniş tarayıcı desteğinden yararlanırken birçok uygulama ayrıntısını soyutlayarak kullanımı kolaylaştırır.
Tarayıcı API'lerini kullanma
Workbox kitaplığı ihtiyaçlarınız için yeterli değilse sayfalar ve Service Worker'lar arasında "iki yönlü" iletişimi uygulamak için kullanılabilecek alt düzey API'ler mevcuttur. Bunların bazı benzerlikleri ve farklılıkları vardır:
Benzerlikler:
- Her durumda, iletişim
postMessage()
arayüzü aracılığıyla bir uçta başlar vemessage
işleyicisi uygulanarak diğer uçta alınır. - Pratikte, mevcut tüm API'ler aynı kullanım alanlarını uygulamamıza olanak tanır. Ancak bazıları, bazı senaryolarda geliştirme sürecini basitleştirebilir.
Farklılıklar:
- İletişimin diğer tarafını tanımlamanın farklı yolları vardır: Bazıları diğer bağlama dair açık bir referans kullanırken diğerleri her iki tarafında somutlaştırılan bir proxy nesnesi aracılığıyla dolaylı yoldan iletişim kurabilir.
- Tarayıcı desteği, ürünler arasında farklılık gösterir.
Yayın Kanalı API'sı
Broadcast Channel API, BroadcastChannel nesneleri aracılığıyla göz atma bağlamları arasında temel iletişime olanak tanır.
Bunu uygulamak için öncelikle her bağlamın aynı kimliğe sahip bir BroadcastChannel
nesnesini örneklendirmesi ve bu nesneden mesaj gönderip alması gerekir:
const broadcast = new BroadcastChannel('channel-123');
BroadcastChannel nesnesi, herhangi bir dinleme bağlamına mesaj göndermek için bir postMessage()
arayüzü sunar:
//send message
broadcast.postMessage({ type: 'MSG_ID', });
Herhangi bir tarayıcı bağlamı, BroadcastChannel
nesnesinin onmessage
yöntemi aracılığıyla mesajları dinleyebilir:
//listen to messages
broadcast.onmessage = (event) => {
if (event.data && event.data.type === 'MSG_ID') {
//process message...
}
};
Görüldüğü gibi, belirli bir bağlama yönelik açık bir referans olmadığı için önce Service Worker'a veya belirli bir istemciye referans alınmasına gerek yoktur.
Dezavantajı, bu yazının hazırlandığı anda API'nin Chrome, Firefox ve Edge'den desteklenmesi ancak Safari gibi diğer tarayıcıların henüz desteklememektedir.
İstemci API'sı
Client API, Service Worker'ın kontrol ettiği etkin sekmeleri temsil eden tüm WindowClient
nesnelerine referans almanızı sağlar.
Sayfa tek bir hizmet çalışanı tarafından kontrol edildiğinden doğrudan serviceWorker
arayüzü üzerinden etkin hizmet çalışanını dinler ve mesaj gönderir:
//send message
navigator.serviceWorker.controller.postMessage({
type: 'MSG_ID',
});
//listen to messages
navigator.serviceWorker.onmessage = (event) => {
if (event.data && event.data.type === 'MSG_ID') {
//process response
}
};
Benzer şekilde, hizmet çalışanı da bir onmessage
işleyicisi uygulayarak mesajları dinler:
//listen to messages
self.addEventListener('message', (event) => {
if (event.data && event.data.type === 'MSG_ID') {
//Process message
}
});
Service Worker, istemcilerinden biriyle tekrar iletişim kurmak için Clients.matchAll()
ve Clients.get()
gibi yöntemleri çalıştırarak bir dizi WindowClient
nesnesi edinir. Bu durumda aşağıdakilerden herhangi birini
postMessage()
yapabilir:
//Obtain an array of Window client objects
self.clients.matchAll(options).then(function (clients) {
if (clients && clients.length) {
//Respond to last focused tab
clients[0].postMessage({type: 'MSG_ID'});
}
});
Client API
, bir Service Worker'ın etkin sekmeleriyle nispeten basit bir şekilde kolayca iletişim kurmak için iyi bir seçenektir. API, başlıca tüm tarayıcılar tarafından desteklenir ancak API'nin tüm yöntemleri mevcut olmayabilir. Bu nedenle, API'yi sitenizde uygulamadan önce tarayıcı desteğini kontrol ettiğinizden emin olun.
Mesaj Kanalı
Mesaj Kanalı, iki yönlü bir iletişim kanalı kurmak için bir bağlantı noktasının tanımlanıp bir bağlamdan diğerine geçirilmesini gerektirir.
Sayfa, kanalı ilk kullanıma hazırlamak için MessageChannel
nesnesini örneklendirir ve bunu kayıtlı hizmet çalışanına bir bağlantı noktası göndermek için kullanır. Sayfa, diğer bağlamdan mesajları almak için ona bir onmessage
işleyicisi de uygular:
const messageChannel = new MessageChannel();
//Init port
navigator.serviceWorker.controller.postMessage({type: 'PORT_INITIALIZATION'}, [
messageChannel.port2,
]);
//Listen to messages
messageChannel.port1.onmessage = (event) => {
// Process message
};
Hizmet çalışanı bağlantı noktasını alır, bağlantı noktasına bir referans kaydeder ve diğer tarafa mesaj göndermek için bunu kullanır:
let communicationPort;
//Save reference to port
self.addEventListener('message', (event) => {
if (event.data && event.data.type === 'PORT_INITIALIZATION') {
communicationPort = event.ports[0];
}
});
//Send messages
communicationPort.postMessage({type: 'MSG_ID'});
MessageChannel
şu anda başlıca tüm tarayıcılar tarafından desteklenmektedir.
Gelişmiş API'ler: Arka Plan Senkronizasyonu ve Arka Plan Getirme
Bu kılavuzda, gerçekleştirilecek işlemi açıklayan bir dize mesajı iletme veya bir bağlamdan diğerine önbelleğe alınacak URL listesi gibi görece basit durumlar için iki yönlü iletişim tekniklerini uygulamanın yollarını araştırdık. Bu bölümde, belirli senaryolara yönelik iki API'yi keşfedeceğiz: bağlantı eksikliği ve uzun indirme işlemleri.
Arka Planda Senkronizasyon
Bir sohbet uygulaması, kötü bağlantı nedeniyle mesajların hiçbir zaman kaybolmadığından emin olmak isteyebilir. Arka Plan Senkronizasyonu API'si kullanıcı kararlı bağlantıya sahip olduğunda işlemlerin yeniden denenmesini ertelemenize olanak tanır. Bu, kullanıcının göndermek istediği şeyin gerçekten gönderildiğinden emin olmak için yararlıdır.
postMessage()
arayüzü yerine sayfa bir sync
kaydeder:
navigator.serviceWorker.ready.then(function (swRegistration) {
return swRegistration.sync.register('myFirstSync');
});
Ardından hizmet çalışanı, mesajı işlemek için sync
etkinliğini dinler:
self.addEventListener('sync', function (event) {
if (event.tag == 'myFirstSync') {
event.waitUntil(doSomeStuff());
}
});
doSomeStuff()
işlevi, yapmaya çalıştığı işlemin başarılı/başarısız olduğunu belirten bir vaat döndürmelidir. Bu işlev işlev görürse senkronizasyon tamamlanır. İşlem başarısız olursa yeniden denemek üzere başka bir senkronizasyon planlanır. Yeniden deneme senkronizasyonları da bağlantıyı bekler ve eksponansiyel geri yükleme uygular.
İşlem gerçekleştirildikten sonra hizmet çalışanı, daha önce ele alınan iletişim API'lerinden herhangi birini kullanarak kullanıcı arayüzünü güncellemek için sayfayla tekrar iletişim kurabilir.
Google arama, kötü bağlantıdan kaynaklanan başarısız sorguları devam ettirmek için Arka Plan Senkronizasyonu'nu kullanır ve bu sorguları daha sonra kullanıcı internete bağlandığında yeniden dener. İşlem gerçekleştirildikten sonra, sonucu kullanıcıya bir web push bildirimi aracılığıyla iletir.
Arka Planda Getirme
İleti gönderme veya önbelleğe alınacak URL listesi gibi nispeten kısa iş parçaları için, şimdiye kadar açıklanan seçenekler iyi bir seçimdir. 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.
Arka Planda Getirme API'si; film, podcast veya bir oyunun seviyelerini indirmek gibi uzun bir görevi Service Worker'a aktarmanıza olanak tanır.
Hizmet çalışanıyla sayfadan iletişim kurmak için postMessage()
yerine backgroundFetch.fetch
kullanın:
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,
},
);
});
BackgroundFetchRegistration
nesnesi, indirme işleminin ilerlemesini izlemek için sayfanın progress
etkinliğini dinlemesini sağlar:
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}%`);
});
Sonraki adımlar
Bu kılavuzda, sayfa ve hizmet çalışanları arasındaki en genel iletişim örneğini (iki yönlü iletişim) inceledik.
Çoğu zaman kullanıcı bir yanıt almadan diğeriyle iletişim kurmak için yalnızca bir içeriğe ihtiyaç duyabilir. Kullanım alanları ve üretim örnekleriyle birlikte, hizmet çalışanından gelen ve hizmet çalışanına giden tek yönlü tekniklerin sayfalarınıza nasıl uygulanacağına ilişkin yol gösterici bilgiler için aşağıdaki rehberlere göz atın:
- Zorunlu önbelleğe alma kılavuzu: Kaynakları önceden önbelleğe almak için sayfadan bir hizmet çalışanının çağrılması (ör. önceden getirme senaryolarında).
- Güncellemeleri yayınlama: Önemli güncellemeler hakkında bilgi vermek için hizmet çalışanının sayfaya çağrı yapması (ör. web uygulamasının yeni bir sürümü kullanılabilir).