Komunikasi dua arah dengan pekerja layanan

Andrew Guan
Andrew Guan
Demián Renzulli
Demián Renzulli

Pada beberapa kasus, aplikasi web mungkin perlu membuat saluran komunikasi dua arah antara dan pekerja layanan.

Misalnya: dalam PWA podcast, seseorang dapat membuat fitur yang memungkinkan pengguna mendownload episode untuk pemakaian offline dan mengizinkan pekerja layanan agar halaman selalu mendapatkan informasi tentang progresnya, sehingga thread dapat mengupdate UI.

Dalam panduan ini, kita akan mempelajari berbagai cara penerapan komunikasi dua arah antara Window dan layanan pekerja, dengan mengeksplorasi berbagai API, library Workbox, untuk beberapa kasus tingkat lanjut.

Diagram yang menampilkan pekerja layanan dan halaman bertukar pesan.

Menggunakan Workbox

workbox-window adalah kumpulan modul library Workbox yang ditujukan untuk untuk dijalankan dalam konteks jendela. Workbox menyediakan metode messageSW() untuk mengirim pesan ke pekerja layanan yang terdaftar pada instance dan menunggu respons.

Kode halaman berikut membuat instance Workbox baru dan mengirim pesan ke pekerja layanan untuk mendapatkan versinya:

const wb = new Workbox('/sw.js');
wb.register();

const swVersion = await wb.messageSW({type: 'GET_VERSION'});
console.log('Service Worker version:', swVersion);

Pekerja layanan mengimplementasikan pemroses pesan di sisi lain, dan merespons permintaan pekerja layanan:

const SW_VERSION = '1.0.0';

self.addEventListener('message', (event) => {
  if (event.data.type === 'GET_VERSION') {
    event.ports[0].postMessage(SW_VERSION);
  }
});

Pada prinsipnya, pustaka ini menggunakan API browser yang akan kita tinjau di bagian berikutnya: Pesan Saluran, tetapi mengabstraksi banyak detail implementasinya, membuatnya lebih mudah digunakan, sambil memanfaatkan browser lebar mendukung API ini.

Diagram yang menunjukkan komunikasi dua arah antara halaman dan pekerja layanan, menggunakan Jendela Workbox.

Menggunakan API Browser

Jika pustaka Workbox tidak cukup untuk kebutuhan Anda, ada beberapa API dengan tingkat menerapkan komunikasi "dua arah" antara halaman dan pekerja layanan. Mereka memiliki beberapa kesamaan dan perbedaan:

Persamaan:

  • Dalam semua kasus, komunikasi dimulai di satu ujung melalui antarmuka postMessage() dan diterima di sisi lain dengan menerapkan pengendali message.
  • Dalam praktiknya, semua API yang tersedia memungkinkan kita untuk menerapkan kasus penggunaan yang sama, tetapi beberapa di antaranya mungkin menyederhanakan pengembangan dalam beberapa skenario.

Perbedaan:

  • Mereka memiliki cara yang berbeda untuk mengidentifikasi sisi lain dari komunikasi: beberapa dari mereka menggunakan secara eksplisit merujuk ke konteks lain, sementara yang lain bisa berkomunikasi secara implisit yang dibuat instance-nya di setiap sisi.
  • Dukungan browser bervariasi di antara opsi tersebut.
Diagram yang menunjukkan komunikasi dua arah antara halaman dan pekerja layanan, serta API browser yang tersedia.

Broadcast Channel API

Dukungan Browser

  • Chrome: 54.
  • Edge: 79.
  • Firefox: 38.
  • Safari: 15.4.

Sumber

Broadcast Channel API memungkinkan komunikasi dasar antara konteks penjelajahan melalui BroadcastChannel Google Cloud Platform.

Untuk menerapkannya, pertama-tama, setiap konteks harus membuat instance objek BroadcastChannel dengan ID yang sama lalu mengirim dan menerima pesan darinya:

const broadcast = new BroadcastChannel('channel-123');

Objek BroadcastChannel mengekspos antarmuka postMessage() untuk mengirim pesan ke semua pemrosesan konteks:

//send message
broadcast.postMessage({ type: 'MSG_ID', });

Konteks browser apa pun dapat memproses pesan melalui metode onmessage dari BroadcastChannel :

//listen to messages
broadcast.onmessage = (event) => {
  if (event.data && event.data.type === 'MSG_ID') {
    //process message...
  }
};

Seperti yang terlihat, tidak ada referensi eksplisit untuk konteks tertentu, jadi tidak perlu memperoleh ke pekerja layanan atau klien tertentu.

Diagram yang menunjukkan komunikasi dua arah antara halaman dan pekerja layanan, menggunakan objek Saluran Siaran.

Kekurangannya adalah, pada saat penulisan ini, API ini memiliki dukungan dari Chrome, Firefox dan Edge, tetapi browser lain, seperti Safari, tidak mendukungnya .

Client API

Dukungan Browser

  • Chrome: 40.
  • Edge: 17.
  • Firefox: 44.
  • Safari: 11.1.

Sumber

Client API memungkinkan Anda mendapatkan referensi ke semua objek WindowClient yang mewakili tab aktif yang dikontrol pekerja layanan.

Karena halaman dikontrol oleh satu pekerja layanan, pekerja layanan akan mendengarkan dan mengirim pesan ke pekerja layanan aktif secara langsung melalui antarmuka serviceWorker:

//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
  }
};

Demikian pula, pekerja layanan memproses pesan dengan menerapkan pemroses onmessage:

//listen to messages
self.addEventListener('message', (event) => {
  if (event.data && event.data.type === 'MSG_ID') {
    //Process message
  }
});

Untuk berkomunikasi kembali dengan kliennya, pekerja layanan memperoleh susunan Objek WindowClient dengan mengeksekusi metode-metode seperti Clients.matchAll() dan Clients.get(). Kemudian dapat postMessage() salah satunya:

//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'});
  }
});
Diagram yang menampilkan pekerja layanan berkomunikasi dengan array klien.

Client API adalah opsi yang bagus untuk berkomunikasi secara mudah dengan semua tab aktif dari pekerja layanan dengan cara yang relatif mudah. API ini didukung oleh semua perusahaan besar browser, tetapi tidak semua metodenya tersedia, jadi pastikan untuk memeriksa dukungan browser sebelum menerapkannya di situs Anda.

Saluran Pesan

Dukungan Browser

  • Chrome: 2.
  • Edge: 12.
  • Firefox: 41.
  • Safari: 5.

Sumber

Saluran Pesan memerlukan mendefinisikan dan meneruskan port dari satu konteks ke konteks lainnya untuk membuat komunikasi dua arah saluran TV Anda.

Untuk menginisialisasi saluran, halaman akan membuat instance objek MessageChannel dan menggunakannya untuk mengirim port ke pekerja layanan terdaftar. Halaman ini juga mengimplementasikan pemroses onmessage di untuk menerima pesan dari konteks lain:

const messageChannel = new MessageChannel();

//Init port
navigator.serviceWorker.controller.postMessage({type: 'PORT_INITIALIZATION'}, [
  messageChannel.port2,
]);

//Listen to messages
messageChannel.port1.onmessage = (event) => {
  // Process message
};
Diagram yang menunjukkan halaman yang melewati port ke pekerja layanan, untuk membangun komunikasi dua arah.

Pekerja layanan menerima port, menyimpan referensi ke port tersebut, dan menggunakannya untuk mengirim pesan ke port lain sisi:

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 saat ini didukung oleh semua perusahaan besar browser.

API Lanjutan: Sinkronisasi Latar Belakang dan Pengambilan Latar Belakang

Dalam panduan ini, kita telah mempelajari cara-cara menerapkan teknik komunikasi dua arah, baik dalam kasus sederhana, seperti meneruskan pesan string yang menjelaskan operasi yang akan dilakukan, atau daftar URL untuk menyimpan {i>cache<i} dari satu konteks ke konteks lainnya. Di bagian ini, kita akan mempelajari dua API untuk menangani skenario: kurangnya konektivitas dan download yang lama.

Sinkronisasi Latar Belakang

Dukungan Browser

  • Chrome: 49.
  • Edge: 79.
  • Firefox: tidak didukung.
  • Safari: tidak didukung.

Sumber

Aplikasi chat mungkin ingin memastikan bahwa pesan tidak pernah hilang karena konektivitas yang buruk. Tujuan Background Sync API memungkinkan Anda menunda tindakan untuk dicoba lagi saat pengguna memiliki konektivitas yang stabil. Hal ini berguna untuk memastikan bahwa apa pun yang ingin dikirim pengguna, sudah dikirim.

Halaman mendaftarkan sync, bukan antarmuka postMessage():

navigator.serviceWorker.ready.then(function (swRegistration) {
  return swRegistration.sync.register('myFirstSync');
});

Pekerja layanan kemudian memproses peristiwa sync untuk memproses pesan:

self.addEventListener('sync', function (event) {
  if (event.tag == 'myFirstSync') {
    event.waitUntil(doSomeStuff());
  }
});

Fungsi doSomeStuff() akan menampilkan promise yang menunjukkan keberhasilan/kegagalan apa pun coba lakukan. Jika terpenuhi, sinkronisasi selesai. Jika gagal, sinkronisasi lain akan dijadwalkan untuk coba lagi. Mencoba ulang sinkronisasi juga menunggu konektivitas, dan menggunakan back-off eksponensial.

Setelah operasi dijalankan, pekerja layanan kemudian dapat berkomunikasi kembali dengan halaman untuk mengupdate UI, dengan menggunakan salah satu API komunikasi yang telah dibahas sebelumnya.

Google Penelusuran menggunakan Sinkronisasi Latar Belakang untuk mempertahankan kueri yang gagal karena konektivitas buruk, lalu coba lagi mereka nanti saat pengguna online. Setelah operasi dilakukan, mereka mengomunikasikan hasilnya kepada pengguna melalui notifikasi push web:

Diagram yang menunjukkan halaman yang melewati port ke pekerja layanan, untuk membangun komunikasi dua arah.

Pengambilan Latar Belakang

Dukungan Browser

  • Chrome: 74.
  • Edge: 79.
  • Firefox: tidak didukung.
  • Safari: tidak didukung.

Sumber

Untuk pekerjaan yang relatif singkat seperti mengirim pesan, atau daftar URL untuk di-cache, opsi sejauh ini adalah pilihan yang bagus. Jika tugas terlalu lama, browser akan mematikan layanan pekerja, jika tidak, hal itu akan mengkhawatirkan privasi dan baterai pengguna.

Background Fetch API memungkinkan Anda mengalihkan tugas yang panjang ke pekerja layanan, seperti mendownload film, podcast, atau level permainan.

Untuk berkomunikasi dengan pekerja layanan dari halaman, gunakan backgroundFetch.fetch, bukan postMessage():

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,
    },
  );
});

Objek BackgroundFetchRegistration memungkinkan halaman memproses peristiwa progress untuk diikuti kemajuan download:

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}%`);
});
Diagram yang menunjukkan halaman yang melewati port ke pekerja layanan, untuk membangun komunikasi dua arah.
UI diupdate untuk menunjukkan progres download (kiri). Berkat pekerja layanan, operasi dapat terus berjalan saat semua tab telah ditutup (kanan).

Langkah berikutnya

Dalam panduan ini kita menjelajahi kasus komunikasi yang paling umum antara halaman dan pekerja layanan (komunikasi dua arah).

Sering kali, satu mungkin hanya memerlukan satu konteks untuk berkomunikasi dengan yang lain, tanpa menerima yang dihasilkan. Lihat panduan berikut untuk mengetahui panduan cara menerapkan teknik searah dalam laman Anda dari dan ke pekerja layanan, bersama dengan kasus penggunaan dan contoh produksi:

  • Panduan penyimpanan dalam cache penting: Memanggil pekerja layanan dari halaman untuk sumber daya cache di awal (misalnya dalam skenario pengambilan data).
  • Update siaran: Memanggil halaman dari pekerja layanan untuk menginformasikan tentang update penting (misalnya, versi baru aplikasi web tersedia).