Streaming Cara Anda untuk Mendapatkan Respons Langsung

Siapa pun yang telah menggunakan pekerja layanan dapat memberi tahu Anda bahwa pekerja layanan bersifat asinkron. Fungsi ini bergantung secara eksklusif pada antarmuka berbasis peristiwa, seperti FetchEvent, dan menggunakan promise untuk memberi sinyal saat operasi asinkron selesai.

Asinkronitas sama pentingnya, meskipun kurang terlihat oleh developer, dalam hal respons yang diberikan oleh pengendali peristiwa pengambilan pekerja layanan. Respons streaming adalah standar emas di sini: respons ini memungkinkan halaman yang membuat permintaan asli untuk mulai menggunakan respons segera setelah bagian data pertama tersedia, dan berpotensi menggunakan parser yang dioptimalkan untuk streaming guna menampilkan konten secara bertahap.

Saat menulis pengendali peristiwa fetch Anda sendiri, biasanya Anda hanya meneruskan metode respondWith() Response (atau promise untuk Response) yang Anda dapatkan melalui fetch() atau caches.match(), dan selesai. Kabar baiknya adalah Response yang dibuat oleh kedua metode tersebut sudah dapat di-streaming. Kabar buruknya adalah Response yang "dibuat secara manual" tidak dapat di-streaming, setidaknya hingga saat ini. Di sinilah Streams API berperan.

Streaming?

Aliran data adalah sumber data yang dapat dibuat dan dimanipulasi secara bertahap, dan menyediakan antarmuka untuk membaca atau menulis potongan data asinkron, hanya sebagian yang mungkin tersedia dalam memori pada waktu tertentu. Untuk saat ini, kita tertarik dengan ReadableStream, yang dapat digunakan untuk membuat objek Response yang diteruskan ke fetchEvent.respondWith():

self.addEventListener('fetch', event => {
    var stream = new ReadableStream({
    start(controller) {
        if (/* there's more data */) {
        controller.enqueue(/* your data here */);
        } else {
        controller.close();
        }
    });
    });

    var response = new Response(stream, {
    headers: {'content-type': /* your content-type here */}
    });

    event.respondWith(response);
});

Halaman yang permintaannya memicu peristiwa fetch akan mendapatkan respons streaming segera setelah event.respondWith() dipanggil, dan akan terus membaca dari streaming tersebut selama pekerja layanan terus enqueue()ing data tambahan. Respons yang mengalir dari service worker ke halaman benar-benar asinkron, dan kita memiliki kontrol penuh atas pengisian streaming.

Penggunaan di dunia nyata

Anda mungkin telah melihat bahwa contoh sebelumnya memiliki beberapa komentar /* your data here */ placeholder, dan tidak memiliki detail implementasi yang sebenarnya. Jadi, seperti apa contohnya di dunia nyata?

Jake Archibald (tidak mengherankan!) memiliki contoh bagus penggunaan streaming untuk menggabungkan respons HTML dari beberapa cuplikan HTML yang di-cache, bersama dengan data "live" yang di-streaming melalui fetch()—dalam hal ini, konten untuk blog-nya

Keuntungan menggunakan respons streaming, seperti yang dijelaskan Jake, adalah browser dapat mengurai dan merender HTML saat di-streaming, termasuk bit awal yang dimuat dengan cepat dari cache, tanpa harus menunggu penarikan seluruh konten blog selesai. Hal ini memanfaatkan sepenuhnya kemampuan rendering HTML progresif browser. Resource lain yang juga dapat dirender secara progresif, seperti beberapa format gambar dan video, juga dapat memperoleh manfaat dari pendekatan ini.

Streaming? Atau shell aplikasi?

Praktik terbaik yang ada terkait penggunaan pekerja layanan untuk mendukung aplikasi web Anda berfokus pada model Shell Aplikasi + konten dinamis. Pendekatan tersebut mengandalkan penyimpanan dalam cache "shell" aplikasi web Anda secara agresif—HTML, JavaScript, dan CSS minimal yang diperlukan untuk menampilkan struktur dan tata letak—lalu memuat konten dinamis yang diperlukan untuk setiap halaman tertentu melalui permintaan sisi klien.

Streaming menghadirkan alternatif untuk model App Shell, yaitu ada respons HTML yang lebih lengkap yang di-streaming ke browser saat pengguna membuka halaman baru. Respons yang di-streaming dapat menggunakan resource yang di-cache—sehingga dapat tetap memberikan bagian awal HTML dengan cepat, bahkan saat offline.—tetapi respons tersebut akhirnya terlihat lebih seperti isi respons tradisional yang dirender server. Misalnya, jika aplikasi web Anda didukung oleh sistem pengelolaan konten yang merender HTML server dengan menggabungkan template parsial, model tersebut akan diterjemahkan langsung ke dalam penggunaan respons streaming, dengan logika pembuatan template direplikasi di pekerja layanan, bukan server Anda. Seperti yang ditunjukkan dalam video berikut, untuk kasus penggunaan tersebut, keunggulan kecepatan yang ditawarkan respons streaming dapat sangat mencolok:

Salah satu keuntungan penting dari streaming seluruh respons HTML, yang menjelaskan mengapa ini adalah alternatif tercepat dalam video, adalah bahwa HTML yang dirender selama permintaan navigasi awal dapat memanfaatkan sepenuhnya parser HTML streaming browser. Potongan HTML yang disisipkan ke dalam dokumen setelah halaman dimuat (seperti yang biasa dilakukan dalam model App Shell) tidak dapat memanfaatkan pengoptimalan ini.

Jadi, jika Anda berada dalam tahap perencanaan penerapan pekerja layanan, model manakah yang harus Anda adopsi: respons streaming yang dirender secara progresif, atau shell ringan yang digabungkan dengan permintaan sisi klien untuk konten dinamis? Jawabannya adalah, tidak mengherankan, bahwa hal ini bergantung: pada apakah Anda memiliki implementasi yang ada yang mengandalkan CMS dan template parsial (keuntungan: streaming); pada apakah Anda mengharapkan payload HTML tunggal yang besar yang akan mendapatkan manfaat dari rendering progresif (keuntungan: streaming); pada apakah aplikasi web Anda paling baik dimodelkan sebagai aplikasi web satu halaman (keuntungan: App Shell); dan pada apakah Anda memerlukan model yang saat ini didukung di beberapa rilis stabil browser (keuntungan: App Shell).

Kami masih berada di tahap awal respons streaming yang didukung pekerja layanan, dan kami berharap dapat melihat berbagai model yang matang dan terutama melihat lebih banyak alat yang dikembangkan untuk mengotomatiskan kasus penggunaan umum.

Mempelajari streaming lebih dalam

Jika Anda membuat streaming yang dapat dibaca sendiri, memanggil controller.enqueue() secara sembarangan mungkin tidak memadai atau efisien. Jake menjelaskan beberapa detail tentang cara metode start(), pull(), dan cancel() dapat digunakan secara bersamaan untuk membuat aliran data yang disesuaikan dengan kasus penggunaan Anda.

Bagi Anda yang menginginkan detail lebih lanjut, spesifikasi Streaming dapat membantu Anda.

Kompatibilitas

Dukungan untuk membuat objek Response di dalam pekerja layanan menggunakan ReadableStream sebagai sumbernya ditambahkan di Chrome 52.

Implementasi pekerja layanan Firefox belum mendukung respons yang didukung oleh ReadableStream, tetapi ada bug pelacakan yang relevan untuk dukungan Streams API yang dapat Anda ikuti.

Progres pada dukungan Streams API tanpa awalan di Edge, beserta dukungan pekerja layanan secara keseluruhan, dapat dilacak di halaman status Platform Microsoft.