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 के इस्तेमाल के सुझाए गए उदाहरण

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

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

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

चरण स्थिति
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'});

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

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

फ़ीचर का पता लगाना

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

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

डेमो

जिन ब्राउज़र पर यह काम करता है उनमें एम्बेड किए गए iframe में या सीधे Glitch पर, WebSocketStream API को काम करते हुए देखा जा सकता है.

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

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

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

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

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

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

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

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

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

मददगार लिंक

आभार

WebSocketStream API को ऐडम राइस और युताका हिरानो ने लागू किया था.