Geri baskı uygulayarak uygulamanızın WebSocket mesajlarında boğulmasını veya bir WebSocket sunucusuna mesajlar göndermesini önleyin.
Arka plan
WebSocket API'si
WebSocket API, kullanıcının tarayıcısı ile sunucu arasında iki yönlü etkileşimli iletişim oturumu açmayı mümkün kılan WebSocket protokolüne bir JavaScript arayüzü sağlar. Bu API ile bir sunucuya mesaj gönderebilir ve sunucuyu yanıt almak için yoklamadan etkinlik odaklı yanıtlar alabilirsiniz.
Streams API
Streams API, JavaScript'in ağ üzerinden alınan veri parçalarının akışlarına programlı bir şekilde erişmesine ve bunları istenen şekilde işlemesine olanak tanır. Akışlar bağlamında geri baskı önemli bir kavramdır. Bu, tek bir akış veya bir zincirleme elektriğin okuma veya yazma hızını düzenlemesini sağlayan işlemdir. Akışın kendisi veya daha sonra boru zincirinde bulunan bir akış hâlâ meşgulse ve henüz daha fazla parçayı kabul etmeye hazır değilse yayını gerektiği şekilde yavaşlatmak için zincir üzerinden geriye doğru bir sinyal gönderir.
Mevcut WebSocket API ile ilgili sorun
Alınan iletilere karşı baskı uygulamak imkansızdır
Mevcut WebSocket API ile mesajlara WebSocket.onmessage
(sunucudan mesaj alındığında çağrılan EventHandler
) içinde tepki verilir.
Yeni bir mesaj alındığında yoğun veri yenileme işlemleri yapması gereken bir uygulamanız olduğunu varsayalım.
Muhtemelen aşağıdaki koda benzer şekilde akışı ayarlarsınız ve process()
çağrısının sonucunu await
olarak ayarlamış olduğunuzdan emin olmalısınız.
// 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);
};
Yanlış! Mevcut WebSocket API'deki sorun, karşı basıncın uygulanmasının mümkün olmamasıdır.
Mesajlar, process()
yönteminin işleyebileceğinden daha hızlı ulaşırsa oluşturma işlemi bu mesajları arabelleğe alarak belleği doldurur, %100 CPU kullanımı nedeniyle yanıt vermez veya her ikisini birden gerçekleştirir.
Gönderilen iletilere karşı basınç uygulamak ergonomik değildir
Gönderilen mesajlara karşı basınç uygulamak mümkündür, ancak bu yöntem verimsiz ve ergonomik olmayan WebSocket.bufferedAmount
özelliğinin sorgulanmasını içerir.
Bu salt okunur özellik, WebSocket.send()
çağrıları kullanılarak sıraya alınan ancak henüz ağa iletilmemiş verilerin bayt sayısını döndürür.
Bu değer, sıraya alınan tüm veriler gönderildikten sonra sıfırlanır ancak WebSocket.send()
yöntemini çağırmaya devam ederseniz artışa devam eder.
WebSocketStream API nedir?
WebSocketStream API, akışları WebSocket API ile entegre ederek var olmayan veya ergonomik olmayan karşı basınç sorununu çözer. Bu, geri basınç ekin hiçbir ek ücret gerektirmeden "ücretsiz" olarak uygulanabileceği anlamına gelir.
WebSocketStream API için önerilen kullanım alanları
Bu API'yi kullanabilecek sitelere örnekler:
- Özellikle video ve ekran paylaşımı olmak üzere etkileşimi sürdürmesi gereken yüksek bant genişliğine sahip WebSocket uygulamaları.
- Benzer şekilde, video yakalama ve tarayıcıda sunucuya yüklenmesi gereken çok fazla veri oluşturan diğer uygulamalar. Ters basınç sayesinde müşteri, bellekte veri biriktirmek yerine veri oluşturmayı durdurabilir.
Mevcut durum
WebSocketStream API'yi kullanma
Giriş örneği
WebSocketStream API, vaatlere dayalı olduğundan modern JavaScript dünyasında bununla başa çıkmanın daha doğal olmasını sağlar.
Yeni bir WebSocketStream
oluşturup bunu WebSocket sunucusunun URL'sini ileterek başlarsınız.
Ardından, bağlantının opened
olmasını beklersiniz. Bu işlem ReadableStream
ve/veya WritableStream
ile sonuçlanır.
ReadableStream.getReader()
yöntemini çağırarak nihayet bir ReadableStreamDefaultReader
elde edersiniz. Daha sonra akış bitene kadar ({value: undefined, done: true}
biçiminde bir nesne döndürene kadar) read()
verilerini alabilirsiniz.
Buna göre, WritableStream.getWriter()
yöntemini çağırarak sonunda bir WritableStreamDefaultWriter
elde edersiniz ve daha sonra bu verileri write()
olarak ekleyebilirsiniz.
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);
}
Ters basınç
Vadedilen geri basınç özelliğine ne olacak?
Yukarıda da belirttiğim gibi, ekstra adımlara gerek kalmadan "ücretsiz" olarak indirebilirsiniz.
process()
daha uzun sürerse bir sonraki mesaj yalnızca ardışık düzen hazır olduğunda tüketilir.
Benzer şekilde WritableStreamDefaultWriter.write()
adımı yalnızca güvenliyse devam eder.
İleri düzey örnekler
WebSocketStream'in ikinci bağımsız değişkeni, gelecekte uzantıya izin vermek için bir seçenek çantasıdır.
Şu anda tek seçenek, WebSocket oluşturucunun ikinci bağımsız değişkeniyle aynı şekilde davranan protocols
'dir:
const chatWSS = new WebSocketStream(CHAT_URL, {protocols: ['chat', 'chatv2']});
const {protocol} = await chatWSS.opened;
Seçilen protocol
ve potansiyel extensions
, WebSocketStream.opened
vaadiyle sunulan sözlüğün bir parçasıdır.
Canlı bağlantıyla ilgili tüm bilgiler bu vaatte sağlanmaktadır, çünkü bağlantının kesilmesi durumunda bilgiler alakalı olmayacaktır.
const {readable, writable, protocol, extensions} = await chatWSS.opened;
Kapalı WebSocketStream bağlantısı hakkında bilgi
WebSocket API'deki WebSocket.onclose
ve WebSocket.onerror
etkinliklerindeki bilgilere artık WebSocketStream.closed
vaadiyle erişilebilir.
Temiz olmayan kapatma durumunda vaat reddedilir. Aksi takdirde, koda ve sunucu tarafından gönderilen nedene çözümlenir.
Olası tüm durum kodları ve anlamları CloseEvent
durum kodları listesinde açıklanmıştır.
const {code, reason} = await chatWSS.closed;
WebSocketStream bağlantısını kapatma
WebSocketStream, AbortController
ile kapatılabilir.
Dolayısıyla, WebSocketStream
oluşturucuya bir AbortSignal
iletin.
const controller = new AbortController();
const wss = new WebSocketStream(URL, {signal: controller.signal});
setTimeout(() => controller.abort(), 1000);
Alternatif olarak, WebSocketStream.close()
yöntemini de kullanabilirsiniz, ancak ana amacı sunucuya gönderilen kodun ve nedenin belirtilmesine izin vermektir.
wss.close({code: 4000, reason: 'Game over'});
Progresif geliştirme ve birlikte çalışabilirlik
Chrome, şu anda WebSocketStream API'yi uygulayan tek tarayıcıdır.
Klasik WebSocket API ile birlikte çalışabilme amacıyla, alınan mesajlara geri baskı uygulanması mümkün değildir.
Gönderilen mesajlara karşı basınç uygulamak mümkündür, ancak bu yöntem verimsiz ve ergonomik olmayan WebSocket.bufferedAmount
özelliğinin sorgulanmasını içerir.
Özellik algılama
WebSocketStream API'nin desteklenip desteklenmediğini kontrol etmek için şunu kullanın:
if ('WebSocketStream' in window) {
// `WebSocketStream` is supported!
}
Demo
Destekleyen tarayıcılarda, WebSocketStream API'yi yerleştirilmiş iframe'de veya doğrudan Glitch'te görebilirsiniz.
Geri bildirim
Chrome ekibi, WebSocketStream API ile ilgili deneyimlerinizi öğrenmek istiyor.
Bize API tasarımı hakkında bilgi verin
API ile ilgili beklediğiniz gibi çalışmayan bir şey mi var? Ya da fikrinizi uygulamak için gereken eksik yöntemler veya özellikler var mı? Güvenlik modeliyle ilgili sorunuz veya yorumunuz mu var? İlgili GitHub deposunda spesifikasyon sorunu oluşturun veya mevcut bir soruna düşüncelerinizi ekleyin.
Uygulamayla ilgili bir sorunu bildirme
Chrome uygulamasında bir hata buldunuz mu?
Yoksa uygulama, spesifikasyondan farklı mı?
new.crbug.com adresinde hata bildiriminde bulunun. Olabildiğince çok ayrıntı eklediğinizden ve basit yeniden oluşturma talimatlarını eklediğinizden emin olun ve Bileşenler kutusuna Blink>Network>WebSockets
yazın.
Glitch, hızlı ve kolay yeniden oluşturma destek kayıtlarını paylaşmak için idealdir.
API'ye desteği gösterin
WebSocketStream API'yi kullanmayı düşünüyor musunuz? Herkese açık desteğiniz, Chrome ekibinin özellikleri önceliklendirmesine yardımcı olur ve diğer tarayıcı satıcılarına bu özellikleri desteklemenin ne kadar kritik olduğunu gösterir.
#WebSocketStream
hashtag'ini kullanarak @ChromiumDev'e tweet gönderin ve bu hashtag'i nerede ve nasıl kullandığınızı bize bildirin.
Faydalı bağlantılar
- Herkese açık açıklayıcı
- WebSocketStream API Demosu | WebSocketStream API Demo kaynağı
- İzleme hatası
- ChromeStatus.com girişi
- Yanıp Sönen Bileşen:
Blink>Network>WebSockets
Teşekkür
WebSocketStream API, Adam Rice ve Yutaka Hirano tarafından uygulanmıştır. Unsplash'te Daan Mooij tarafından hazırlanan lokomotif resim.