WebSocketStream: WebSocket API के साथ स्ट्रीम इंटिग्रेट करना

बैकप्रेशर लागू करके, अपने ऐप्लिकेशन को WebSocket मैसेज में डूबने या WebSocket सर्वर को मैसेज से भरने से रोकें.

बैकग्राउंड

WebSocket API, WebSocket प्रोटोकॉल के लिए JavaScript इंटरफ़ेस उपलब्ध कराता है. इससे उपयोगकर्ता के ब्राउज़र और सर्वर के बीच, दोतरफ़ा इंटरैक्टिव कम्यूनिकेशन सेशन खोला जा सकता है. इस एपीआई की मदद से, सर्वर पर मैसेज भेजे जा सकते हैं और इवेंट के आधार पर जवाब पाए जा सकते हैं. इसके लिए, सर्वर पर जवाब देने के लिए वोट करना ज़रूरी नहीं है.

Streams API

Streams API, JavaScript को इस बात की अनुमति देता है कि वह नेटवर्क पर मिलने वाले डेटा हिस्से की स्ट्रीम को प्रोग्राम के हिसाब से ऐक्सेस कर सके और उन्हें अपने हिसाब से प्रोसेस कर सके. स्ट्रीम के संदर्भ में एक अहम कॉन्सेप्ट है बैकप्रेस. यह एक ऐसी प्रोसेस है जिसमें एक स्ट्रीम या पाइप चेन, पढ़ने या लिखने की स्पीड को कंट्रोल करती है. जब स्ट्रीम या पाइप चेन में मौजूद कोई स्ट्रीम अब भी व्यस्त है और ज़्यादा चंक स्वीकार करने के लिए तैयार नहीं है, तो वह चेन के ज़रिए पीछे की ओर एक सिग्नल भेजती है, ताकि डिलीवरी को धीमा किया जा सके.

मौजूदा WebSocket API में समस्या है

मिलने वाले मैसेज पर बैक प्रेशर लागू नहीं किया जा सकता

मौजूदा WebSocket API के ज़रिए, मैसेज पर प्रतिक्रिया WebSocket.onmessage में दी जाती है. सर्वर से मैसेज मिलने पर इसे EventHandler कॉल किया जाता है.

मान लें कि आपके पास कोई ऐसा ऐप्लिकेशन है, जिसे नया संदेश प्राप्त होने पर भी बड़ी डेटा क्रंचिंग कार्रवाई करनी है. ऐसे में, नीचे दिए गए कोड से मिलता-जुलता फ़्लो सेट अप किया जा सकता है और process() कॉल के नतीजे को await करने की वजह से, सही है न?

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

गलत! मौजूदा WebSocket API की समस्या यह है कि बैकप्रेशर लागू करने का कोई तरीका नहीं है. जब मैसेज, process() तरीके से हैंडल किए जाने से ज़्यादा जल्दी पहुंच जाते हैं, तो रेंडर करने की प्रोसेस, उन मैसेज को बफ़र करके मेमोरी भरती है. हालांकि, 100% सीपीयू के इस्तेमाल से या इन दोनों तरीकों से, ये मैसेज काम नहीं करते.

भेजे गए मैसेज पर बैकप्रेशर लागू करना, काम के हिसाब से नहीं है

भेजे गए मैसेज पर बैकप्रेस का इस्तेमाल किया जा सकता है. हालांकि, इसमें WebSocket.bufferedAmount प्रॉपर्टी की पोलिंग शामिल की जा सकती है. यह सुविधा कम कारगर है और इसमें ज़्यादा एर्गोनॉमिक्स नहीं है. यह रीड-ओनली प्रॉपर्टी, डेटा के बाइट की वह संख्या दिखाती है जो WebSocket.send() को कॉल का इस्तेमाल करके सूची में हैं. हालांकि, इसे अभी नेटवर्क पर ट्रांसमिट नहीं किया गया है. सूची में मौजूद सारा डेटा भेजे जाने के बाद, यह वैल्यू शून्य पर रीसेट हो जाती है. हालांकि, WebSocket.send() को कॉल करते रहने पर, यह वैल्यू बढ़ती रहेगी.

WebSocketStream API क्या है?

WebSocketStream API, WebSocket API के साथ स्ट्रीम को इंटिग्रेट करके, गैर-मौजूद या नॉन-एर्गोनॉमिक बैकप्रेस की समस्या का समाधान करता है. इसका मतलब है कि बैकप्रेस को बिना किसी और शुल्क के "मुफ़्त" में लागू किया जा सकता है.

WebSocketStream API के इस्तेमाल के सुझाए गए उदाहरण

उन साइटों के उदाहरण जो इस एपीआई का इस्तेमाल कर सकती हैं:

  • हाई बैंडविथ WebSocket ऐप्लिकेशन, जिन्हें खास तौर पर वीडियो और स्क्रीन शेयर करने में इंटरैक्टिविटी को बनाए रखने की ज़रूरत होती है.
  • इसी तरह, वीडियो कैप्चर और दूसरे ऐप्लिकेशन जो ब्राउज़र में बहुत ज़्यादा डेटा जनरेट करते हैं, जिन्हें सर्वर पर अपलोड करने की ज़रूरत होती है. बैकप्रेशर की मदद से, क्लाइंट मेमोरी में डेटा इकट्ठा करने के बजाय, डेटा जनरेट करना बंद कर सकता है.

मौजूदा स्थिति

चरण स्थिति
1. एक्सप्लेनर वीडियो बनाना पूरा हुआ
2. स्पेसिफ़िकेशन का शुरुआती ड्राफ़्ट बनाएं प्रोसेस जारी है
3. सुझाव/राय इकट्ठा करना और डिज़ाइन में बदलाव करना प्रोसेस जारी है
4. ऑरिजिन ट्रायल पूरा हुआ
5. लॉन्च करें समीक्षा शुरू नहीं हुई है

WebSocketStream API को इस्तेमाल करने का तरीका

WebSocketStream API, प्रॉमिस पर आधारित है. इसलिए, इसे आधुनिक JavaScript की दुनिया में आसानी से इस्तेमाल किया जा सकता है. आपको एक नया WebSocketStream बनाना होगा और फिर उसे WebSocket सर्वर का यूआरएल पास करना होगा. इसके बाद, आपको कनेक्शन के opened होने का इंतज़ार करना होगा, जिससे आपको ReadableStream और/या WritableStream दिखेगा.

ReadableStream.getReader() तरीके का इस्तेमाल करने पर, आपको एक ReadableStreamDefaultReader मिलता है. इससे read() से तब तक का डेटा मिलता है, जब तक कि स्ट्रीम पूरी नहीं हो जाती. इसमें तब तक का डेटा होता है, जब तक कि उससे फ़ॉर्म का कोई ऑब्जेक्ट नहीं दिखता है{value: undefined, done: true}.

इसी तरह, WritableStream.getWriter() तरीके का इस्तेमाल करने पर, आपको WritableStreamDefaultWriter मिलता है, जिससे write() में डेटा इकट्ठा किया जा सकता है.

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

बैकप्रेशर

उस सुविधा का क्या होगा जिसके बारे में दावा किया गया था? आपको यह "बिना किसी शुल्क के" मिलता है. इसके लिए, आपको कुछ और करने की ज़रूरत नहीं है. अगर process() को ज़्यादा समय लगता है, तो अगला मैसेज सिर्फ़ तब इस्तेमाल किया जाता है, जब पाइपलाइन तैयार हो जाती है. इसी तरह, WritableStreamDefaultWriter.write() चरण सिर्फ़ तब आगे बढ़ना है, जब ऐसा करना सुरक्षित हो.

बेहतर उदाहरण

WebSocketStream का दूसरा आर्ग्युमेंट, एक विकल्पों का बैग है. इससे आने वाले समय में एक्सटेंशन की अनुमति मिलती है. सिर्फ़ protocols विकल्प है, जो WebSocket कन्स्ट्रक्टर के दूसरे आर्ग्युमेंट की तरह ही काम करता है:

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

चुने गए protocol और संभावित extensions, WebSocketStream.opened प्रॉमिस के ज़रिए उपलब्ध डिक्शनरी का हिस्सा हैं. लाइव कनेक्शन के बारे में सारी जानकारी, इस वादे में दी गई है, क्योंकि कनेक्शन न होने पर यह जानकारी काम की नहीं है.

const {readable, writable, protocol, extensions} = await chatWSS.opened;

WebSocketStream कनेक्शन के बारे में जानकारी

WebSocket API में WebSocket.onclose और WebSocket.onerror इवेंट से मिलने वाली जानकारी, अब WebSocketStream.closed प्रॉमिस के ज़रिए उपलब्ध है. गलत तरीके से बंद किए जाने पर प्रॉमिस अस्वीकार हो जाता है, नहीं तो यह सर्वर से भेजे गए कोड और वजह के आधार पर रिज़ॉल्व हो जाता है.

CloseEvent स्टेटस कोड की सूची में, सभी संभावित स्टेटस कोड और उनके मतलब के बारे में बताया गया है.

const {code, reason} = await chatWSS.closed;

WebSocketStream कनेक्शन बंद करना

WebSocketStream को AbortController की मदद से बंद किया जा सकता है. इसलिए, WebSocketStream कन्स्ट्रक्टर को AbortSignal पास करें.

const controller = new AbortController();
const wss = new WebSocketStream(URL, {signal: controller.signal});
setTimeout(() => controller.abort(), 1000);

एक विकल्प के तौर पर, WebSocketStream.close() तरीके का इस्तेमाल भी किया जा सकता है. इसका मुख्य मकसद, सर्वर को भेजे जाने वाले कोड और वजह की जानकारी देना है.

wss.close({code: 4000, reason: 'Game over'});

प्रोग्रेसिव एन्हैंसमेंट और इंटरऑपरेबिलिटी

फ़िलहाल, सिर्फ़ Chrome ऐसा ब्राउज़र है जिस पर WebSocketStream API लागू किया जा सकता है. क्लासिक WebSocket API के साथ इंटरऑपरेबिलिटी के लिए, मिले मैसेज पर बैकप्रेशर लागू नहीं किया जा सकता. भेजे गए मैसेज पर बैकप्रेशर लागू किया जा सकता है. हालांकि, इसके लिए WebSocket.bufferedAmount प्रॉपर्टी को पोल करना पड़ता है, जो कि असरदार और सुविधाजनक नहीं है.

सुविधा की पहचान

WebSocketStream API काम करता है या नहीं, यह देखने के लिए:

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

डेमो

साथ काम करने वाले ब्राउज़र पर, एम्बेड किए गए iframe में या सीधे Glitch पर, WebSocketStream API का इस्तेमाल किया जा सकता है.

सुझाव/राय दें या शिकायत करें

Chrome की टीम, WebSocketStream API के इस्तेमाल से जुड़े आपके अनुभवों के बारे में जानना चाहती है.

हमें एपीआई के डिज़ाइन के बारे में बताएं

क्या एपीआई में ऐसा कुछ है जो आपकी उम्मीद के मुताबिक काम नहीं करता? क्या आपके आइडिया को लागू करने के लिए, कोई तरीका या प्रॉपर्टी मौजूद नहीं है? क्या आपके पास सुरक्षा मॉडल से जुड़ा कोई सवाल या टिप्पणी है? इससे जुड़े GitHub रेपो पर, स्पेसिफ़िकेशन की समस्या दर्ज करें या किसी मौजूदा समस्या के बारे में अपनी राय दें.

लागू करने से जुड़ी समस्या की शिकायत करना

क्या आपको Chrome को लागू करने में कोई गड़बड़ी मिली? या क्या इसे लागू करने का तरीका, खास जानकारी से अलग है? new.crbug.com पर जाकर, गड़बड़ी की शिकायत करें. ज़्यादा से ज़्यादा जानकारी दें. साथ ही, गड़बड़ी को दोहराने के लिए आसान निर्देश दें. इसके बाद, Components बॉक्स में Blink>Network>WebSockets डालें. Glitch, रिप्रोडक्शन के मामलों को कम समय में और आसानी से शेयर करने के लिए बेहतरीन काम करता है.

एपीआई के लिए सहायता दिखाना

क्या आपको WebSocketStream API का इस्तेमाल करना है? सार्वजनिक तौर पर सहायता करने से, Chrome की टीम को सुविधाओं को प्राथमिकता देने में मदद मिलती है. साथ ही, इससे अन्य ब्राउज़र वेंडर को यह पता चलता है कि इन सुविधाओं को उपलब्ध कराना कितना ज़रूरी है.

#WebSocketStream हैशटैग का इस्तेमाल करके, @ChromiumDev को ट्वीट करें और हमें बताएं कि इसका इस्तेमाल कहां और कैसे किया जा रहा है.

मददगार लिंक

धन्यवाद

WebSocketStream API को Adam Rice और Yutaka Hirano ने लागू किया था.