Bazı durumlarda, bir web uygulamasının sayfa ile hizmet çalışanı arasında iki yönlü bir iletişim kanalı oluşturması gerekebilir.
Örneğin, bir podcast PWA'sında kullanıcının bölümleri çevrimdışı izlemek için indirmesine ve hizmet çalışanının sayfayı ilerleme durumu hakkında düzenli olarak bilgilendirmesine izin veren bir özellik oluşturabilirsiniz. Böylece ana iş akışı kullanıcı arayüzünü güncelleyebilir.
Bu kılavuzda, farklı API'leri, Workbox kitaplığını ve bazı gelişmiş örnekleri inceleyerek pencere ile hizmet işleyici bağlamı arasında iki yönlü iletişimi uygulamanın farklı yollarını keşfedeceğiz.
Workbox'u kullanma
workbox-window
, Workbox kitaplığının pencere bağlamında çalıştırılması amaçlanan bir modül grubudur. Workbox
sınıfı, örneğin kayıtlı hizmet işçisine mesaj gönderip 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ü almak 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);
Servis çalışanı, diğer tarafta bir mesaj dinleyici uygular ve kayıtlı servis ç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ık, arka planda bir tarayıcı API'si kullanır. Bu API'yi sonraki bölümde inceleyeceğiz: MessageChannel. Ancak kitaplık, birçok uygulama ayrıntısını soyutlayarak bu API'nin geniş tarayıcı desteğinden yararlanırken kullanımını kolaylaştırır.
Tarayıcı API'lerini Kullanma
Workbox kitaplığı ihtiyaçlarınız için yeterli değilse sayfalar ve hizmet çalışanları arasında "iki yönlü" iletişimi uygulamak için kullanabileceğiniz birkaç alt düzey API vardır. Bu iki yöntemin bazı benzerlikleri ve farklılıkları vardır:
Benzerlikler:
- Tüm durumlarda iletişim, bir uçta
postMessage()
arayüzü üzerinden başlar ve diğer uçta birmessage
işleyici uygulanarak alınır. - Pratikte, mevcut tüm API'ler aynı kullanım alanlarını uygulamamıza olanak tanır ancak bazı API'ler bazı senaryolarda geliştirmeyi basitleştirebilir.
Farklılıklar:
- İletişimin diğer tarafını tanımlamanın farklı yolları vardır: Bazıları diğer bağlama açık bir şekilde referans verirken bazıları her iki tarafta örneklenen bir proxy nesnesi aracılığıyla dolaylı yoldan iletişim kurabilir.
- Tarayıcı desteği, bu sürümler arasında değişiklik gösterir.
Broadcast Channel API
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
nesnesi oluşturması ve bu nesne üzerinden ileti gönderip alması gerekir:
const broadcast = new BroadcastChannel('channel-123');
BroadcastChannel nesnesi, dinleyen herhangi bir bağlama 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öntemini kullanarak 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 dair açık bir referans yoktur. Bu nedenle, önce Service Worker'a veya belirli bir istemciye referansta bulunmaya gerek yoktur.
Dezavantajı, bu makalenin yazıldığı sırada API'nin Chrome, Firefox ve Edge tarafından desteklenmesi ancak Safari gibi diğer tarayıcıların henüz desteklememesidir.
Client API
İstemci API'si, hizmet çalışanının kontrol ettiği etkin sekmeleri temsil eden tüm WindowClient
nesnelerine referans almanıza olanak tanır.
Sayfa tek bir hizmet çalışanı tarafından kontrol edildiğinden, etkin hizmet çalışanını doğrudan serviceWorker
arayüzü üzerinden dinler ve ona 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ı bir onmessage
işleyici uygulayarak mesajları dinler:
//listen to messages
self.addEventListener('message', (event) => {
if (event.data && event.data.type === 'MSG_ID') {
//Process message
}
});
Hizmet çalışanı, müşterileriyle geri iletişim kurmak için Clients.matchAll()
ve Clients.get()
gibi yöntemleri yürüterek bir dizi WindowClient
nesnesi elde eder. Ardından aşağıdaki işlemler postMessage()
:
//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 hizmet çalışanından tüm etkin sekmelerle nispeten basit bir şekilde kolayca iletişim kurmak için iyi bir seçenektir. API, tüm büyük tarayıcılar tarafından desteklenir ancak tüm yöntemleri kullanılamayabilir. Bu nedenle, API'yi sitenize uygulamadan önce tarayıcı desteğini kontrol edin.
Mesaj Kanalı
Mesaj Kanalı, iki yönlü bir iletişim kanalı oluşturmak için bir bağlantı noktasını tanımlamayı ve bir bağlamdan diğerine iletmeyi gerektirir.
Sayfa, kanalı başlatmak için bir MessageChannel
nesnesi oluşturur ve kayıtlı hizmet işçisine bağlantı göndermek için bu nesneyi kullanır. Sayfa, diğer bağlamdan mesaj almak için üzerinde bir onmessage
dinleyici 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 ait bir referans kaydeder ve diğer tarafa mesaj göndermek için bu referansı 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 tüm büyük tarayıcılar tarafından desteklenmektedir.
Gelişmiş API'ler: Arka Plan Senkronizasyonu ve Arka Planda Getirme
Bu kılavuzda, yapılacak işlemi açıklayan bir dize mesajı veya bir bağlamdan diğerine önbelleğe alınacak URL'lerin listesi gibi nispeten basit durumlarda iki yönlü iletişim tekniklerini uygulamanın yollarını inceledik. Bu bölümde, belirli senaryoları (bağlantı olmaması ve uzun indirmeler) ele almak için iki API'yi inceleyeceğiz.
Arka Plan Senkronizasyonu
Bir sohbet uygulaması, mesajların zayıf bağlantı nedeniyle kaybolmadığından emin olmak isteyebilir. Arka Plan Senkronizasyonu API'si, kullanıcının bağlantısı sabit olduğunda yeniden denenecek işlemleri ertelemenize olanak tanır. Bu, kullanıcının göndermek istediği her şeyin gerçekten gönderilmesini sağlamak için kullanışlıdır.
Sayfa, postMessage()
arayüzü yerine 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ı olup olmadığını belirten bir promise döndürmelidir. İşlev başarılı olursa senkronizasyon tamamlanır. Bu işlem başarısız olursa yeniden denemek için başka bir senkronizasyon planlanır. Yeniden deneme senkronizasyonları da bağlantı kurulmasını bekler ve eksponansiyel geri çekme uygular.
İşlem gerçekleştirildikten sonra hizmet çalışanı, daha önce keşfedilen 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ı nedeniyle başarısız olan sorguları korumak ve kullanıcı internete bağlıyken bunları daha sonra yeniden denemek için Arka Plan Senkronizasyonu'nu kullanır. İşlem gerçekleştirildikten sonra sonuç, web push bildirimi aracılığıyla kullanıcıya iletilir:
Arka planda getirme
İleti gönderme veya önbelleğe alınacak URL'lerin listesi gibi nispeten kısa işlemler için şimdiye kadar keşfedilen seçenekler iyi bir seçimdir. Görev çok uzun sürerse tarayıcı, hizmet çalışanını sonlandıracaktır. Aksi takdirde bu, kullanıcının gizliliği ve pili için risk oluşturabilir.
Arka Planda Getirme API'si, film, podcast veya oyun seviyesi indirme gibi uzun süren bir görevi hizmet işleyiciye devretmenize olanak tanır.
Sayfadan hizmet çalışanıyla 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, sayfanın indirme işleminin ilerleme durumunu takip etmek için progress
etkinliğini dinlemesine olanak tanır:
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 ile hizmet işçileri arasındaki en genel iletişim durumunu (iki yönlü iletişim) inceledik.
Çoğu zaman, bir kullanıcının yanıt almadan diğer kullanıcıyla iletişim kurması için yalnızca bir bağlama ihtiyacı olabilir. Sayfalarınızda Service Worker'dan veya hizmet çalışanına doğru tek yönlü teknikler uygulamakla ilgili yönergeler, kullanım alanları ve üretim örnekleri için aşağıdaki kılavuzlara göz atın:
- Zorunlu önbelleğe alma kılavuzu: Kaynakları önceden önbelleğe almak için sayfadan bir hizmet çalışanı çağırma (ör. ön getirme senaryolarında).
- Güncellemeleri yayınlama: Önemli güncellemeler (ör. web uygulamasının yeni bir sürümü kullanıma sunuldu) hakkında bilgi vermek için sayfayı hizmet çalışanından çağırma.