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

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

| Adım | Durum | | ------------------------------------------ | ---------------------------- | | 1. Açıklayıcı oluşturma | [Tamamlama][açıklama] | | 2. Spesifikasyonun ilk taslağını oluşturun | [Devam ediyor][spesifikasyon] | | 3. Geri bildirim toplama ve tasarımda yineleme | [Devam ediyor](#feedback) | | 4. Kaynak denemesi | [Tamamlandı][ot] | | 5. Lansman | Başlatılmadı |

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

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.