Cegah aplikasi Anda agar tidak kewalahan menerima pesan WebSocket atau membanjiri server WebSocket dengan pesan dengan menerapkan tekanan balik.
Latar belakang
WebSocket API menyediakan antarmuka JavaScript ke protokol WebSocket, yang memungkinkan sesi komunikasi interaktif dua arah dibuka antara browser pengguna dan server. Dengan API ini, Anda dapat mengirim pesan ke server dan menerima respons berbasis peristiwa tanpa melakukan polling server untuk mendapatkan balasan.
Streams API
Streams API memungkinkan JavaScript mengakses secara terprogram aliran potongan data yang diterima melalui jaringan dan memprosesnya sesuai keinginan. Konsep penting dalam konteks aliran adalah backpressure. Proses ini adalah proses yang digunakan oleh satu aliran atau rangkaian saluran untuk mengatur kecepatan membaca atau menulis. Jika streaming itu sendiri atau streaming di rantai pipeline masih sibuk dan belum siap menerima lebih banyak chunk, streaming akan mengirimkan sinyal kembali melalui rantai untuk memperlambat pengiriman sebagaimana mestinya.
Masalah dengan WebSocket API saat ini
Tidak mungkin menerapkan tekanan balik ke pesan yang diterima
Dengan WebSocket API saat ini, reaksi terhadap pesan terjadi di
WebSocket.onmessage
,
EventHandler
yang dipanggil saat pesan diterima dari server.
Misalkan Anda memiliki aplikasi yang perlu melakukan operasi pemrosesan data berat
setiap kali ada pesan baru yang diterima.
Anda mungkin akan menyiapkan alur yang mirip dengan kode di bawah,
dan karena Anda await
hasil panggilan process()
, Anda akan baik-baik saja, bukan?
// A heavy data crunching operation.
const process = async (data) => {
return new Promise((resolve) => {
window.setTimeout(() => {
console.log('WebSocket message processed:', data);
return resolve('done');
}, 1000);
});
};
webSocket.onmessage = async (event) => {
const data = event.data;
// Await the result of the processing step in the message handler.
await process(data);
};
Salah! Masalah dengan WebSocket API saat ini adalah tidak ada cara untuk menerapkan backpressure.
Jika pesan tiba lebih cepat daripada yang dapat ditangani oleh metode process()
,
proses rendering akan mengisi memori dengan mem-buffer pesan tersebut,
menjadi tidak responsif karena penggunaan CPU 100%, atau keduanya.
Menerapkan tekanan balik pada pesan yang dikirim tidak ergonomis
Penerapan tekanan balik pada pesan yang dikirim dapat dilakukan, tetapi melibatkan polling properti
WebSocket.bufferedAmount
, yang tidak efisien dan tidak ergonomis.
Properti hanya baca ini menampilkan jumlah byte data yang telah diantrekan
menggunakan panggilan ke
WebSocket.send()
,
tetapi belum ditransmisikan ke jaringan.
Nilai ini akan direset ke nol setelah semua data dalam antrean dikirim,
tetapi jika Anda terus memanggil WebSocket.send()
,
nilai ini akan terus bertambah.
Apa itu WebSocketStream API?
WebSocketStream API mengatasi masalah tekanan balik yang tidak ada atau tidak ergonomis dengan mengintegrasikan stream dengan WebSocket API. Artinya, tekanan balik dapat diterapkan "tanpa biaya", tanpa biaya tambahan.
Kasus penggunaan yang disarankan untuk WebSocketStream API
Contoh situs yang dapat menggunakan API ini meliputi:
- Aplikasi WebSocket bandwidth tinggi yang perlu mempertahankan interaktivitas, khususnya video dan berbagi layar.
- Demikian pula, pengambilan video dan aplikasi lain yang menghasilkan banyak data di browser yang perlu diupload ke server. Dengan tekanan balik, klien dapat berhenti menghasilkan data daripada mengakumulasi data dalam memori.
Status saat ini
Langkah | Status |
---|---|
1. Membuat penjelasan | Selesai |
2. Buat draf awal spesifikasi | Sedang diproses |
3. Mengumpulkan masukan & mengulangi desain | Sedang diproses |
4. Uji coba origin | Selesai |
5. Luncurkan | Belum dimulai |
Cara menggunakan WebSocketStream API
WebSocketStream API berbasis promise, sehingga terasa alami saat digunakan
di dunia JavaScript modern.
Anda mulai dengan membuat WebSocketStream
baru dan meneruskan URL server WebSocket ke WebSocketStream
tersebut.
Selanjutnya, Anda menunggu koneksi menjadi opened
,
yang menghasilkan
ReadableStream
dan/atau
WritableStream
.
Dengan memanggil metode
ReadableStream.getReader()
, Anda akhirnya mendapatkan
ReadableStreamDefaultReader
,
yang kemudian dapat Anda read()
data darinya hingga aliran data selesai, yaitu hingga menampilkan objek dalam bentuk
{value: undefined, done: true}
.
Oleh karena itu, dengan memanggil metode WritableStream.getWriter()
, Anda akhirnya mendapatkan WritableStreamDefaultWriter
, yang kemudian dapat Anda gunakan untuk write()
data.
const wss = new WebSocketStream(WSS_URL);
const {readable, writable} = await wss.opened;
const reader = readable.getReader();
const writer = writable.getWriter();
while (true) {
const {value, done} = await reader.read();
if (done) {
break;
}
const result = await process(value);
await writer.write(result);
}
Tekanan balik
Bagaimana dengan fitur tekanan balik yang dijanjikan?
Anda mendapatkannya "tanpa biaya", tidak perlu langkah tambahan.
Jika process()
memerlukan waktu tambahan, pesan berikutnya hanya akan digunakan setelah pipeline siap.
Demikian pula, langkah WritableStreamDefaultWriter.write()
hanya dilanjutkan jika aman.
Contoh lanjutan
Argumen kedua ke WebSocketStream adalah kumpulan opsi untuk memungkinkan ekstensi di masa mendatang.
Satu-satunya opsi adalah protocols
, yang berperilaku sama seperti
argumen kedua untuk konstruktor WebSocket:
const chatWSS = new WebSocketStream(CHAT_URL, {protocols: ['chat', 'chatv2']});
const {protocol} = await chatWSS.opened;
protocol
yang dipilih serta potensi extensions
adalah bagian dari kamus yang tersedia melalui promise WebSocketStream.opened
.
Semua informasi tentang koneksi langsung diberikan oleh promise ini,
karena tidak relevan jika koneksi gagal.
const {readable, writable, protocol, extensions} = await chatWSS.opened;
Informasi tentang koneksi WebSocketStream yang ditutup
Informasi yang tersedia dari peristiwa
WebSocket.onclose
dan
WebSocket.onerror
di WebSocket API kini tersedia melalui janji WebSocketStream.closed
.
Promise ditolak jika terjadi penutupan yang tidak bersih,
jika tidak, promise akan diselesaikan ke kode dan alasan yang dikirim oleh server.
Semua kemungkinan kode status dan artinya dijelaskan dalam
daftar kode status CloseEvent
.
const {code, reason} = await chatWSS.closed;
Menutup koneksi WebSocketStream
WebSocketStream dapat ditutup dengan
AbortController
.
Oleh karena itu, teruskan AbortSignal
ke konstruktor WebSocketStream
. AbortController.abort()
hanya berfungsi sebelum handshake, bukan setelahnya.
const controller = new AbortController();
const wss = new WebSocketStream(URL, {signal: controller.signal});
setTimeout(() => controller.abort(), 1000);
Sebagai alternatif, Anda juga dapat menggunakan metode WebSocketStream.close()
,
tetapi tujuan utamanya adalah untuk mengizinkan penentuan
kode
dan alasan yang dikirim ke server.
wss.close({closeCode: 4000, reason: 'Game over'});
Peningkatan progresif dan interoperabilitas
Saat ini, Chrome adalah satu-satunya browser yang mengimplementasikan WebSocketStream API.
Untuk interoperabilitas dengan WebSocket API klasik, penerapan tekanan balik pada pesan yang diterima tidak memungkinkan.
Penerapan tekanan balik pada pesan yang dikirim dapat dilakukan, tetapi melibatkan polling properti
WebSocket.bufferedAmount
, yang tidak efisien dan tidak ergonomis.
Deteksi fitur
Untuk memeriksa apakah WebSocketStream API didukung, gunakan:
if ('WebSocketStream' in window) {
// `WebSocketStream` is supported!
}
Demo
Di browser yang mendukung, Anda dapat melihat cara kerja WebSocketStream API di iframe yang disematkan, atau langsung di Glitch.
Masukan
Tim Chrome ingin mengetahui pengalaman Anda menggunakan WebSocketStream API.
Beri tahu kami tentang desain API
Apakah ada sesuatu tentang API yang tidak berfungsi seperti yang Anda harapkan? Atau, apakah ada metode atau properti yang hilang yang Anda butuhkan untuk menerapkan ide Anda? Ada pertanyaan atau komentar tentang model keamanan? Laporkan masalah spesifikasi di repo GitHub yang sesuai, atau tambahkan pendapat Anda ke masalah yang ada.
Melaporkan masalah terkait penerapan
Apakah Anda menemukan bug pada penerapan Chrome?
Atau apakah implementasinya berbeda dengan spesifikasi?
Laporkan bug di new.crbug.com.
Pastikan untuk menyertakan detail sebanyak mungkin, petunjuk sederhana untuk mereproduksi,
dan masukkan Blink>Network>WebSockets
di kotak Komponen.
Menunjukkan dukungan untuk API
Apakah Anda berencana menggunakan WebSocketStream API? Dukungan publik Anda membantu tim Chrome memprioritaskan fitur dan menunjukkan kepada vendor browser lain betapa pentingnya dukungan untuk fitur tersebut.
Kirim tweet ke @ChromiumDev menggunakan hashtag
#WebSocketStream
dan beri tahu kami di mana dan bagaimana Anda menggunakannya.
Link bermanfaat
- Penjelasan publik
- Demo WebSocketStream API | Sumber demo WebSocketStream API
- Melacak bug
- Entri ChromeStatus.com
- Komponen Blink:
Blink>Network>WebSockets
Ucapan terima kasih
WebSocketStream API diimplementasikan oleh Adam Rice dan Yutaka Hirano.