Cegah aplikasi Anda tenggelam dalam pesan WebSocket atau membanjiri server WebSocket dengan pesan dengan menerapkan backpressure.
Latar belakang
WebSocket API
WebSocket API menyediakan antarmuka JavaScript ke protokol WebSocket, yang memungkinkan untuk membuka sesi komunikasi interaktif dua arah antara browser pengguna dan server. Dengan API ini, Anda dapat mengirim pesan ke server dan menerima respons berbasis peristiwa tanpa melakukan polling ke server untuk membalas.
Streams API
Streams API memungkinkan JavaScript untuk mengakses secara terprogram aliran potongan data yang diterima melalui jaringan dan memprosesnya sesuai keinginan. Konsep penting dalam konteks {i>stream <i}adalah tekanan balik. Ini adalah proses di mana aliran tunggal atau rantai pipa mengatur kecepatan membaca atau menulis. Saat stream itu sendiri atau stream nanti dalam rantai pipa masih sibuk dan belum siap untuk menerima lebih banyak bagian, sistem mengirimkan sinyal mundur melalui rantai untuk memperlambat pengiriman yang sesuai.
Masalah dengan WebSocket API saat ini
Tidak mungkin menerapkan backpressure ke pesan yang diterima
Dengan WebSocket API saat ini, bereaksi terhadap pesan terjadi di
WebSocket.onmessage
,
EventHandler
yang dipanggil saat pesan diterima dari server.
Anggaplah Anda memiliki aplikasi yang perlu melakukan operasi pemrosesan data yang berat
setiap kali pesan baru diterima.
Anda mungkin akan mengatur alur
yang mirip dengan kode di bawah ini,
dan karena Anda await
hasil panggilan process()
, seharusnya Anda 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 pada WebSocket API saat ini adalah tidak ada cara untuk menerapkan backpressure.
Saat pesan masuk lebih cepat daripada metode process()
yang dapat menanganinya,
proses {i>render<i} akan memenuhi memori
dengan cara menyangga pesan-pesan tersebut,
menjadi tidak responsif karena 100% penggunaan CPU, atau keduanya.
Menerapkan backpressure ke pesan yang dikirim bersifat tidak ergonomis
Menerapkan {i>backpressure<i} ke pesan yang dikirim dapat dilakukan, tetapi melibatkan polling
WebSocket.bufferedAmount
properti, yang tidak efisien dan tidak ergonomis.
Properti hanya-baca ini menampilkan jumlah byte data yang telah dimasukkan dalam antrean
menggunakan panggilan ke
WebSocket.send()
,
tetapi belum ditransmisikan ke jaringan.
Nilai ini diatur ulang ke nol setelah semua data dalam antrean terkirim,
tetapi jika Anda terus memanggil WebSocket.send()
,
jalannya akan terus menanjak.
Apa itu WebSocketStream API?
WebSocketStream API menangani masalah tekanan balik yang tidak ada atau tidak ergonomis dengan mengintegrasikan stream dengan WebSocket API. Artinya, backpressure dapat diterapkan "secara gratis", tanpa biaya tambahan.
Kasus penggunaan yang disarankan untuk WebSocketStream API
Contoh situs yang dapat menggunakan API ini antara lain:
- Aplikasi WebSocket dengan bandwidth tinggi yang perlu mempertahankan interaktivitas, khususnya video dan berbagi layar.
- Demikian pula, perekaman video dan aplikasi lain yang menghasilkan banyak data di browser yang perlu diupload ke server. Dengan backpressure, klien dapat berhenti menghasilkan data, bukan mengumpulkan data dalam memori.
Status saat ini
Langkah | Status |
---|---|
1. Buat penjelasan | Selesai |
2. Membuat draf awal spesifikasi | Dalam proses |
3. Kumpulkan masukan & mengulangi desain | Dalam proses |
4. Uji coba origin | Selesai |
5. Luncurkan | Belum dimulai |
Cara menggunakan WebSocketStream API
Contoh pengantar
WebSocketStream API berbasis promise, sehingga penanganannya terasa alami
di dunia JavaScript modern.
Anda mulai dengan membuat WebSocketStream
baru dan meneruskan URL server WebSocket ke sini.
Selanjutnya, tunggu koneksi menjadi opened
,
yang menghasilkan
ReadableStream
dan/atau
WritableStream
.
Dengan memanggil metode
ReadableStream.getReader()
, Anda akhirnya mendapatkan sebuah
ReadableStreamDefaultReader
,
yang kemudian dapat Anda read()
data mulai dari hingga streaming selesai, yaitu, hingga menampilkan objek berupa
{value: undefined, done: true}
.
Oleh karena itu, dengan memanggil
WritableStream.getWriter()
, Anda akhirnya mendapatkan sebuah
WritableStreamDefaultWriter
,
yang kemudian dapat Anda write()
datanya.
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 backpressure yang dijanjikan?
Seperti yang saya tulis di atas, Anda dapat menikmatinya "secara gratis", tanpa perlu langkah tambahan.
Jika process()
memerlukan waktu tambahan, pesan berikutnya hanya akan digunakan setelah pipeline siap.
Demikian pula, langkah WritableStreamDefaultWriter.write()
hanya akan dilanjutkan jika aman untuk melakukannya.
Contoh lanjutan
Argumen kedua untuk WebSocketStream adalah tas opsi untuk memungkinkan ekstensi di masa mendatang.
Saat ini, satu-satunya opsi adalah protocols
,
yang berperilaku sama dengan
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
tersedia melalui promise WebSocketStream.opened
.
Semua informasi tentang koneksi langsung
disediakan oleh promise ini,
karena tidak relevan jika koneksi gagal.
const {readable, writable, protocol, extensions} = await chatWSS.opened;
Informasi tentang koneksi WebSocketStream tertutup
Informasi yang tersedia dari
WebSocket.onclose
dan
Peristiwa WebSocket.onerror
di WebSocket API sekarang tersedia melalui promise WebSocketStream.closed
.
Janji itu ditolak jika terjadi penutupan yang tidak bersih,
jika tidak maka akan merujuk pada kode dan
alasan yang dikirim oleh server.
Semua kemungkinan kode status dan artinya dijelaskan di
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
.
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 memungkinkan penentuan
kode
dan alasan yang
dikirim ke server.
wss.close({code: 4000, reason: 'Game over'});
Interoperabilitas dan progressive enhancement
Saat ini, Chrome adalah satu-satunya browser yang menerapkan WebSocketStream API.
Untuk interoperabilitas dengan WebSocket API klasik,
tidak mungkin menerapkan backpressure ke
pesan yang diterima.
Menerapkan {i>backpressure<i} ke pesan yang dikirim dapat dilakukan, tetapi melibatkan polling
WebSocket.bufferedAmount
properti, 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 pendukung, Anda dapat melihat aksi WebSocketStream API di iframe tersemat, atau langsung di Glitch.
Masukan
Tim Chrome ingin mengetahui pengalaman Anda saat 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 diperlukan untuk menerapkan ide Anda? Ada pertanyaan atau komentar tentang model keamanan? Ajukan masalah spesifikasi di repo GitHub yang sesuai, atau sampaikan pendapat Anda tentang masalah yang sudah ada.
Laporkan masalah terkait penerapan
Apakah Anda menemukan bug pada implementasi Chrome?
Atau apakah implementasinya berbeda dengan spesifikasi?
Laporkan bug di new.crbug.com.
Pastikan untuk menyertakan detail sebanyak mungkin, petunjuk sederhana untuk reproduksi,
dan masukkan Blink>Network>WebSockets
di kotak Components.
Glitch sangat cocok untuk berbagi kasus reproduksi dengan cepat dan mudah.
Menunjukkan dukungan untuk API
Anda berencana menggunakan WebSocketStream API? Dukungan publik Anda membantu tim Chrome untuk memprioritaskan fitur serta menunjukkan kepada vendor browser lain betapa pentingnya mendukung mereka.
Kirim tweet ke @ChromiumDev menggunakan hashtag
#WebSocketStream
dan beri tahu kami tempat serta
cara Anda menggunakannya.
Link bermanfaat
- Penjelasan untuk publik
- Demo WebSocketStream API | Sumber Demo WebSocketStream API
- Bug pelacakan
- Entri ChromeStatus.com
- Komponen Kedipan:
Blink>Network>WebSockets
Ucapan terima kasih
WebSocketStream API diimplementasikan oleh Adam Rice dan Yutaka Hirano. Banner besar oleh Daan Mooij di Buka pembuka.