WebSocketStream: Akışları WebSocket API ile entegre etme

Ters basınç uygulayarak uygulamanızın WebSocket mesajlarında boğulmasını veya bir WebSocket sunucusunu iletilerle doldurmasını önleyin.

Arka plan

WebSocket API, WebSocket protokolü için bir JavaScript arayüzü sağlar. Bu arayüz, kullanıcının tarayıcısı ile sunucu arasında iki yönlü etkileşimli bir iletişim oturumu açmayı mümkün kılar. Bu API ile sunucuya mesaj gönderebilir ve sunucuyu yanıt almak için yoklamadan etkinliğe dayalı yanıtlar alabilirsiniz.

Streams API

Streams API, JavaScript'in ağ üzerinden alınan veri parçası akışlarına programatik olarak erişmesine ve bunları istenen şekilde işlemesine olanak tanır. Akışlar bağlamında önemli bir kavram geri bastırmadır. Bu, okuma veya yazma hızının tek bir akış ya da boru zinciriyle düzenlenmesidir. Akış veya ardışık düzen zincirinin sonraki bir yayını hâlâ meşgulse ve daha fazla parçayı kabul etmeye hazır değilse yayın, zincir boyunca geriye doğru bir sinyal göndererek yayını uygun şekilde yavaşlatır.

Mevcut WebSocket API'sindeki sorun

Alınan mesajlara geri basınç uygulamak mümkün değildir.

Mevcut WebSocket API ile bir iletiye tepki, WebSocket.onmessage içinde gerçekleşir. Bu da sunucudan bir ileti alındığında EventHandler olarak anılır.

Her yeni mesaj alındığında ağır veri işlemesi işlemleri yapması gereken bir uygulamanız olduğunu varsayalım. Akışınızı büyük olasılıkla aşağıdaki koda benzer şekilde ayarlarsınız. process() çağrısının sonucunu await ettiğiniz için sorun yaşamazsınız, değil mi?

// 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ınç uygulamanın bir yolunun olmamasıdır. Mesajlar, process() yönteminin işleyebileceğinden daha hızlı geldiğinde oluşturma işlemi bu mesajları arabelleğe alarak belleği doldurur, %100 CPU kullanımı nedeniyle yanıt vermez veya her ikisini birden yapar.

Gönderilen iletilere karşı basınç uygulamak ergonomik değildir

Gönderilen mesajlara geri basınç uygulamak mümkündür ancak WebSocket.bufferedAmount mülkünü yoklamak gerekir. Bu işlem hem verimsiz hem de ergonomik değildir. Bu salt okunur mülk, WebSocket.send() çağrıları kullanılarak sıraya eklenen ancak henüz ağa aktarılmayan bayt sayısı döndürür. Bu değer, sıraya alınan tüm veriler gönderildikten sonra sıfıra sıfırlanır ancak WebSocket.send() çağrısını yapmaya devam ederseniz değer artmaya devam eder.

WebSocketStream API nedir?

WebSocketStream API, akışları WebSocket API ile entegre ederek geri basınç olmaması veya ergonomik olmaması sorununu çözer. Bu, baskının herhangi bir ek maliyet olmadan "ücretsiz" olarak uygulanabileceği anlamına gelir.

WebSocketStream API için önerilen kullanım alanları

Bu API'yi kullanılabilecek sitelere örnek olarak şunlar verilebilir:

  • Özellikle video ve ekran paylaşımında, etkileşimi sürdürmesi gereken yüksek bant genişliğine sahip WebSocket uygulamaları.
  • Benzer şekilde, video yakalama ve tarayıcıda büyük miktarda veri üreten ve sunucuya yüklenmesi gereken diğer uygulamalar. Karşı basınç sayesinde istemci, verileri bellekte biriktirmek yerine veri üretmeyi durdurabilir.

Mevcut durum

Step Durum
1. Açıklayıcı oluşturun Tamamlandı
2. Spesifikasyonun ilk taslağını oluşturma Devam ediyor
3. Geri bildirim alma ve tasarım üzerinde yineleme Devam ediyor
4. Kaynak denemesi Tamamlandı
5. Başlat Başlatılmadı

WebSocketStream API'yi kullanma

WebSocketStream API vaat temellidir. Bu nedenle, modern JavaScript dünyasında bu API'yle uğraşmak doğal bir deneyim haline gelir. Yeni bir WebSocketStream oluşturarak ve ona WebSocket sunucusunun URL'sini ileterek başlarsınız. Ardından, bağlantının opened olmasını bekleyin. Bu, ReadableStream ve/veya WritableStream ile sonuçlanır.

ReadableStream.getReader() yöntemini çağırarak nihayet bir ReadableStreamDefaultReader elde edersiniz. Daha sonra bu verileri read(), akış tamamlanana kadar, yani {value: undefined, done: true} formunun bir nesnesini döndürene kadar kullanabilirsiniz.

Buna göre, WritableStream.getWriter() yöntemini çağırarak nihayet bir WritableStreamDefaultWriter elde edersiniz. Daha sonra bunu write() yapabilirsiniz.

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

Geri basınç

Söz edilen karşı basınç özelliğine ne olacak? "Ücretsiz" olarak alırsınız, ek işlem yapmanız gerekmez. process() daha fazla zaman alırsa bir sonraki mesaj yalnızca ardışık düzen hazır olduğunda tüketilir. Benzer şekilde, WritableStreamDefaultWriter.write() adımı da yalnızca güvenli olduğunda devam eder.

İleri düzey örnekler

WebSocketStream'in ikinci bağımsız değişkeni, gelecekte uzatmaya olanak tanıyan bir seçenek çantasıdır. Yalnızca protocols seçeneği kullanılabilir. Bu seçenek, WebSocket kurucusunun ikinci bağımsız değişkeni ile aynı şekilde çalışır:

const chatWSS = new WebSocketStream(CHAT_URL, {protocols: ['chat', 'chatv2']});
const {protocol} = await chatWSS.opened;

Seçilen protocol ve potansiyel extensions, WebSocketStream.opened taahhüdüyle sunulan sözlüğün bir parçasıdır. Bağlantının başarısız olması önemli olmadığından, canlı bağlantıyla ilgili tüm bilgiler bu taahhüt kapsamında sağlanı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 etkinliklerinden elde edilen bilgilere artık WebSocketStream.closed sözü ile ulaşabilirsiniz. Vaat, açık olmayan bir kapatma durumunda reddedilir. Aksi takdirde, sunucu tarafından gönderilen koda ve 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. Bu nedenle, 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 bu yöntemin asıl amacı, kodu ve sunucuya gönderilen nedeni belirtmenize 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ışabilirlik için alınan mesajlara geri baskı uygulamak mümkün değildir. Gönderilen mesajlara geri basınç uygulamak mümkündür ancak WebSocket.bufferedAmount mülkünü yoklamak gerekir. Bu işlem hem verimsiz hem de ergonomik değildir.

Özellik algılama

WebSocketStream API'nin desteklenip desteklenmediğini kontrol etmek için şunu kullanın:

if ('WebSocketStream' in window) {
  // `WebSocketStream` is supported!
}

Demo

Desteklenen tarayıcılarda WebSocketStream API'yi yerleşik 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 olarak beklediğiniz gibi çalışmayan bir şey var mı? Yoksa fikrinizi uygulamak için ihtiyaç duyduğunuz yöntemler veya özellikler eksik mi? Güvenlik modeliyle ilgili bir sorunuz veya yorumunuz mu var? İlgili GitHub deposunda spesifikasyon sorunu oluşturun veya mevcut bir soruna düşüncelerinizi ekleyin.

Uygulamayla ilgili bir sorunu bildirin

Chrome'un uygulamasında bir hata mı buldunuz? Yoksa uygulama, spesifikasyondan farklı mı? new.crbug.com adresinden hata kaydı oluşturun. Mümkün olduğunca fazla ayrıntı ekleyin, hatayı yeniden oluşturmayla ilgili basit talimatlar verin ve Bileşenler kutusuna Blink>Network>WebSockets yazın. Glitch, yeniden oluşturma vakalarını hızlı ve kolay bir şekilde paylaşmak için idealdir.

API'ye desteğinizi gösterin

WebSocketStream API'yi kullanmayı planlıyor musunuz? Herkese açık desteğiniz, Chrome ekibinin özellikleri önceliklendirmesine yardımcı olur ve diğer tarayıcı tedarikçilerine bunları desteklemenin ne kadar kritik olduğunu gösterir.

#WebSocketStream hashtag'ini kullanarak @ChromiumDev hesabına tweet gönderin ve bu özelliği nerede ve nasıl kullandığınızı bize bildirin.

Faydalı bağlantılar

Teşekkür

WebSocketStream API, Adam Rice ve Yutaka Hirano tarafından uygulanmıştır.