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ığındaki 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 sunduğu 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 ile hizmet çalışanları arasında "iki yönlü" iletişimi uygulamak için kullanılabilecek 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şleyicisi 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 referans verirken diğerleri her iki tarafta da oluşturulan bir proxy nesnesi aracılığıyla dolaylı olarak 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 tarama 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', });
Tüm tarayıcı bağlamları, 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 açık bir referans verilmemiştir. Bu nedenle, önce hizmet çalışanına veya belirli bir müşteriye referans almanız gerekmez.
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
dinleyici 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ğıdakilerden birini yapabilirsiniz:
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ı eksikliği ve uzun indirmeler) ele almak için iki API'yi inceleyeceğiz.
Arka Plan Senkronizasyonu
Sohbet uygulamaları, kötü bağlantı nedeniyle mesajların hiçbir zaman kaybolmamasını sağlayabilir. 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 ş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. Senkronizasyonların yeniden denenmesi de bağlantıyı bekler ve üstel geri yükleme kullanır.
İş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ırır. Aksi takdirde kullanıcının gizliliği ve pili riske atılmış olur.
Arka Planda Getirme API'si, film, podcast veya oyun seviyesi indirme gibi uzun süren bir görevi hizmet işleyiciye aktarmanıza 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 şeklini (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 servis işleyiciye ve servis işleyiciden tek yönlü teknikleri nasıl uygulayacağınızla ilgili yol gösterici bilgiler, 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.