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

Geri basınç uygulayarak uygulamanızın WebSocket mesajlarıyla boğulmasını veya bir WebSocket sunucusunu mesajlarla doldurmasını önleyin.

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, bir sunucuya mesaj gönderebilir ve sunucudan yanıt almak için anket yapmadan olaya dayalı yanıtlar alabilirsiniz.

Streams API

Streams API, JavaScript'in ağ üzerinden alınan veri parçaları akışlarına programatik olarak erişmesine ve bunları istediği gibi işlemesine olanak tanır. Akış bağlamında önemli bir kavram da geri basınçtır. Bu, tek bir akış veya boru zincirinin okuma ya da yazma hızını düzenlediği işlemdir. 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 ile ilgili sorun

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

Mevcut WebSocket API'de, bir mesaja tepki verme işlemi WebSocket.onmessage içinde gerçekleşir. Bu, sunucudan bir mesaj alındığında çağrılan bir EventHandler'tır.

Yeni bir mesaj alındığında yoğun veri işleme 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'nin sorunu, geri basınç uygulamanın mümkün olmamasıdır. Mesajlar, process() yönteminin işleyebileceğinden daha hızlı geldiğinde oluşturma işlemi ya bu mesajları arabelleğe alarak belleği doldurur, ya% 100 CPU kullanımı nedeniyle yanıt vermez hale gelir ya da her ikisini birden yapar.

Gönderilen mesajlara geri 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, geri basıncın ek ücret ödemeden "ücretsiz" olarak uygulanabileceği anlamına gelir.

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

Bu API'yi kullanabilen sitelere örnek olarak şunlar verilebilir:

  • Özellikle video ve ekran paylaşımı olmak üzere etkileşimi koruması gereken yüksek bant genişliğine sahip WebSocket uygulamaları.
  • Benzer şekilde, tarayıcıda çok fazla veri oluşturan ve sunucunun yüklemesi gereken diğer uygulamalar da bu kapsamdadır. Geri basınç sayesinde istemci, verileri bellekte biriktirmek yerine veri üretmeyi durdurabilir.

Mevcut durum

Step Durum
1. Açıklayıcı oluşturma Tamamlandı
2. Spesifikasyonun ilk taslağını oluşturma Devam ediyor
3. Geri bildirim toplayın ve tasarımda iterasyon yapın Devam ediyor
4. Kaynak denemesi Tamamlandı
5. Başlat Başlatılmadı

WebSocketStream API'yi kullanma

WebSocketStream API'si, modern JavaScript dünyasında doğal bir şekilde kullanılabilmesi için söze dayalı bir API'dir. 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() metodunu çağırarak bir ReadableStreamDefaultReader elde edersiniz. Bu read(), akış tamamlanana kadar yani {value: undefined, done: true} biçiminde bir nesne döndürene kadar veri alabilir.

Bu nedenle, WritableStream.getWriter() yöntemini çağırarak bir WritableStreamDefaultWriter elde edersiniz. Bu write() veri 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);
  }

Geri basınç

Söz verilen geri basınç özelliği 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 uzantıya izin vermek için bir seçenek paketidir. Tek seçenek protocols'tür. Bu seçenek, WebSocket oluşturucusunun 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 olası extensions, WebSocketStream.opened vaadi aracılığıyla kullanılabilen 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 edilebilen bilgiler artık WebSocketStream.closed promise aracılığıyla kullanılabilir. Sözleşme, temiz olmayan bir kapatma durumunda reddeder. 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ı, sunucuya gönderilecek kodu ve 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 basınç uygulamak mümkün değildir. Gönderilen mesajlara geri basınç uygulamak mümkündür ancak WebSocket.bufferedAmount mülkünü yoklamayı gerektirir. Bu işlem hem verimsiz hem de ergonomik değildir.

Özellik algılama

WebSocketStream API'nin desteklenip desteklenmediğini kontrol etmek için:

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

Demo

Desteklenen tarayıcılarda, WebSocketStream API'yi yerleşik iFrame'de veya doğrudan Glitch'te çalışırken görebilirsiniz.

Geri bildirim

Chrome Ekibi, WebSocketStream API ile ilgili deneyimlerinizi öğrenmek istiyor.

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 sorunuz veya yorumunuz mu var? İlgili GitHub deposunda özellik sorunu oluşturun veya mevcut bir soruna düşüncelerinizi ekleyin.

Uygulamayla ilgili sorunları bildirme

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, hataları hızlı ve kolay bir şekilde paylaşmak için idealdir.

API'yi destekleme

WebSocketStream API'yi kullanmayı planlıyor musunuz? Herkese açık desteğiniz, Chrome ekibinin özelliklere öncelik vermesine yardımcı olur ve diğer tarayıcı tedarikçi firmalarına bu özellikleri desteklemenin ne kadar önemli 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 ederiz

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