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ışı tüketim için indirmesine olanak tanıyan bir özellik oluşturulabilir ve hizmet çalışanı, sayfayı düzenli olarak ilerleme durumu hakkında bilgilendirebilir. Böylece ana iş parçacığı kullanıcı arayüzünü güncelleyebilir.
Bu rehberde, farklı API'leri, Workbox kitaplığını ve bazı gelişmiş durumları inceleyerek pencere ile service worker bağlamı arasında iki yönlü iletişimi uygulamanın farklı yollarını ele alacağız.

Workbox'ı kullanma
workbox-window
, pencere bağlamında çalışması amaçlanan Workbox kitaplığının bir dizi modülüdür. Workbox
sınıfı, örneğin kayıtlı hizmet çalışanına mesaj göndermek ve yanıt beklemek için messageSW()
yöntemini sağlar.
Aşağıdaki sayfa kodu yeni bir Workbox
örneği oluşturur ve hizmet çalışanının sürümünü almak için hizmet çalışanına 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 uçta bir mesaj dinleyici uygular ve kayıtlı service worker'a 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 bir sonraki bölümde inceleyeceğiz: MessageChannel. Ancak birçok uygulama ayrıntısını soyutlayarak kullanımını kolaylaştırır ve bu API'nin sahip olduğu geniş tarayıcı desteğinden yararlanır.

Tarayıcı API'lerini kullanma
Workbox kitaplığı ihtiyaçlarınızı karşılamıyorsa 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 hizmet arasında bazı benzerlikler ve farklılıklar vardır:
Benzerlikler:
- Her durumda iletişim, bir uçta
postMessage()
arayüzü üzerinden başlar ve diğer uçtamessage
işleyici uygulanarak alınır. - Uygulamada, mevcut tüm API'ler aynı kullanım alanlarını uygulamamıza olanak tanır ancak bazıları bazı senaryolarda geliştirmeyi basitleştirebilir.
Farklılıklar:
- İletişimin diğer tarafını tanımlamak için farklı yöntemler kullanırlar: Bazıları diğer bağlama açıkça atıfta bulunurken bazıları da her iki tarafta oluşturulan bir proxy nesnesi aracılığıyla örtülü olarak iletişim kurabilir.
- Tarayıcı desteği, bu uygulamalar arasında farklılık 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.
Bu özelliği uygulamak için öncelikle her bağlamın aynı kimliğe sahip bir BroadcastChannel
nesnesi oluşturması ve bu nesneden mesaj göndermesi ve alması gerekir:
const broadcast = new BroadcastChannel('channel-123');
BroadcastChannel nesnesi, dinleyen herhangi bir bağlama mesaj göndermek için postMessage()
arayüzünü kullanıma sunar:
//send message
broadcast.postMessage({ type: 'MSG_ID', });
Herhangi bir tarayıcı bağlamı, BroadcastChannel
nesnesinin onmessage
yöntemiyle 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ça atıfta bulunulmuyor. Bu nedenle, önce hizmet çalışanı veya belirli bir istemciye referans almak gerekmiyor.

Dezavantajı ise bu yazı yazıldığı sırada API'nin Chrome, Firefox ve Edge tarafından destekleniyor olması ancak Safari gibi diğer tarayıcıların henüz desteklememesidir.
Client API
Client API, 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, serviceWorker
arayüzü aracılığıyla doğrudan etkin hizmet çalışanını 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ı da onmessage
dinleyicisi uygulayarak iletileri dinler:
//listen to messages
self.addEventListener('message', (event) => {
if (event.data && event.data.type === 'MSG_ID') {
//Process message
}
});
Service worker, istemcileriyle iletişim kurmak için Clients.matchAll()
ve Clients.get()
gibi yöntemleri yürüterek WindowClient
nesnelerinden oluşan bir dizi alır. Ardından, bu cihazlardan postMessage()
herhangi birini 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 hizmet çalışanındaki 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, sitenizde uygulamadan önce tarayıcı desteğini kontrol ettiğinizden emin olun.
Mesaj Kanalı
Message Channel, iki yönlü bir iletişim kanalı oluşturmak için bir bağlantı noktasının tanımlanmasını ve bir bağlamdan diğerine aktarılmasını gerektirir.
Sayfa, kanalı başlatmak için bir MessageChannel
nesnesi oluşturur ve bunu, kayıtlı servis çalışanına bir bağlantı noktası göndermek için kullanır. Sayfada, diğer bağlamdan mesaj almak için bir onmessage
işleyici de uygulanır:
const messageChannel = new MessageChannel();
//Init port
navigator.serviceWorker.controller.postMessage({type: 'PORT_INITIALIZATION'}, [
messageChannel.port2,
]);
//Listen to messages
messageChannel.port1.onmessage = (event) => {
// Process message
};

Service worker, bağlantı noktasını alır, bağlantı noktasına 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, nispeten basit durumlar için (ör. gerçekleştirilecek işlemi açıklayan bir dize mesajı veya bir bağlamdan diğerine önbelleğe alınacak URL listesi geçirme) iki yönlü iletişim tekniklerini uygulama yöntemlerini ele aldık. 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ı, kötü bağlantı nedeniyle iletilerin hiçbir zaman kaybolmamasını sağlamak isteyebilir. Arka Plan Senkronizasyonu API'si, kullanıcının bağlantısı kararlı olduğunda yeniden denenmek üzere 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 sync
kaydediyor:
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ı veya başarısız olduğunu belirten bir söz döndürmelidir. Söz yerine getirilirse senkronizasyon tamamlanır. Başarısız olursa yeniden denemek için başka bir senkronizasyon planlanır. Yeniden denenen senkronizasyonlar da bağlantı için bekler ve eksponansiyel geri yükleme kullanır.
İşlem gerçekleştirildikten sonra hizmet çalışanı, daha önce incelenen iletişim API'lerinden herhangi birini kullanarak kullanıcı arayüzünü güncellemek için sayfayla tekrar iletişim kurabilir.
Google Arama, bağlantı kalitesinin düşük olması nedeniyle başarısız olan sorguları kalıcı hale getirmek ve kullanıcı internete bağlandığında bunları daha sonra yeniden denemek için arka plan senkronizasyonunu kullanır. İşlem gerçekleştirildikten sonra sonuç, web push bildirimi aracılığıyla kullanıcıya iletilir:

Arka planda getirme
Mesaj gönderme veya önbelleğe alınacak URL listesi gibi nispeten kısa işler için şu ana kadar incelenen 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 pil ömrü risk altında olur.
Background Fetch API, uzun süren görevleri (ör. film, podcast veya oyun seviyesi indirme) bir hizmet çalışanına devretmenize olanak tanır.
Sayfadan hizmet çalışanına 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 çalışanları arasındaki iletişimin en genel durumunu (iki yönlü iletişim) ele aldık.
Çoğu zaman, yanıt almadan diğeriyle iletişim kurmak için tek bir bağlam yeterli olabilir. Hizmet çalışanından sayfalarınıza ve sayfalarınızdan hizmet çalışanına tek yönlü teknikleri uygulama, kullanım alanları ve üretim örnekleri hakkında bilgi edinmek 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. önceden getirme senaryolarında).
- Yayın güncellemeleri: Önemli güncellemeler (ör. web uygulamasının yeni bir sürümü kullanıma sunuldu) hakkında bilgi vermek için sayfayı service worker'dan çağırma.