4 पॉइंट द्वारा GN⁺ 2026-02-28 | 1 टिप्पणियां | WhatsApp पर शेयर करें
  • Web Streams मानक को ब्राउज़र और सर्वर के बीच एकसमान डेटा स्ट्रीमिंग के लिए डिज़ाइन किया गया था, लेकिन फिलहाल जटिलता और प्रदर्शन सीमाओं के कारण डेवलपर अनुभव खराब हो रहा है
  • मौजूदा API में lock प्रबंधन, BYOB, backpressure जैसी डिज़ाइन सीमाएँ हैं, जो उपयोग और implementation दोनों में अनावश्यक बोझ पैदा करती हैं
  • Cloudflare ने async iteration पर आधारित एक नया stream model प्रस्तावित किया है, और यह तरीका 2 गुना से लेकर अधिकतम 120 गुना तेज प्रदर्शन दिखाता है
  • नया API सरल async iterable संरचना, स्पष्ट backpressure policies, और sync/async समानांतर समर्थन के जरिए दक्षता और एकरूपता बढ़ाता है
  • यह तरीका Node.js, Deno, Bun, ब्राउज़र आदि सभी runtimes में एकीकृत streaming model को संभव बना सकता है, और आगे चलकर standards discussion की शुरुआत बन सकता है

Web Streams की संरचनात्मक सीमाएँ

  • WHATWG Streams मानक 2014~2016 के बीच विकसित किया गया था और ब्राउज़र-केंद्रित रूप से डिज़ाइन हुआ था; उस समय async iteration मौजूद नहीं थी, इसलिए अलग reader/writer model अपनाया गया
    • इसके कारण lock प्रबंधन, जटिल read loop, BYOB buffer handling जैसी अनावश्यक प्रक्रियाएँ पैदा हुईं
  • locking model stream पर एकाधिकार कर देता है और समानांतर consumption को रोकता है; releaseLock() छूट जाने पर stream स्थायी रूप से lock हो सकती है
  • BYOB(Bring Your Own Buffer) फीचर का लक्ष्य memory reuse था, लेकिन जटिल buffer separation/transfer model के कारण इसका वास्तविक उपयोग कम रहा और implementation कठिन हो गई
  • backpressure सिद्धांततः समर्थित है, लेकिन desiredSize मान negative होने पर भी enqueue() सफल हो जाता है, इसलिए वास्तविक नियंत्रण संभव नहीं है
  • हर read() call पर Promise बनाना अनिवार्य है, जिससे high-frequency streaming में performance गिरती है और GC पर लोड बढ़ता है

व्यवहारिक उपयोग में सामने आई समस्याएँ

  • fetch() response body को consume न करने पर connection pool exhaustion हो सकता है, और tee() उपयोग करने पर unbounded memory buffering पैदा होती है
  • TransformStream read readiness की परवाह किए बिना तुरंत process करता है, जिससे slow consumer environments में buffer explosion हो सकता है
  • server-side rendering(SSR) में हज़ारों छोटे chunks को process करने से GC thrashing होती है और performance तेजी से गिरती है
  • हर runtime(Node.js, Deno, Bun, Workers) ने इसे कम करने के लिए non-standard optimization paths जोड़े, लेकिन इससे compatibility और consistency कम हुई
  • Web Platform Tests में 70 से अधिक जटिल test files की ज़रूरत पड़ती है, जो अत्यधिक internal state management और non-intuitive behavior का नतीजा है

नए stream API के design principles

  • stream को एक सरल async iterable के रूप में परिभाषित किया गया है, इसलिए इसे for await...of से सीधे consume किया जा सकता है
  • pull-through transformation अपनाई गई है, ताकि processing तभी हो जब consumer डेटा मांगे
  • स्पष्ट backpressure policies(strict, block, drop-oldest, drop-newest) दी गई हैं, ताकि memory runaway रोकी जा सके
  • डेटा को batch chunks(Uint8Array[]) में भेजा जाता है, जिससे Promise creation cost कम होती है
  • सिर्फ byte-oriented processing रखकर इसे सरल बनाया गया है, और BYOB या जटिल controller concepts हटा दिए गए हैं
  • synchronous path support से CPU-केंद्रित कामों में Promise overhead हट जाता है

नए API के उदाहरण और विशेषताएँ

  • Stream.push() से आसानी से writer/readable pair बनाया जा सकता है, और Stream.text() से पूरा text एकत्र किया जा सकता है
  • Stream.pull() lazy pipeline बनाता है, जो केवल consumption के समय execute होती है
  • Stream.share() और Stream.broadcast() स्पष्ट multi-consumer management का समर्थन करते हैं
  • Sync/Async parallel API(Stream.pullSync(), Stream.textSync()) I/O-रहित operations में performance को अधिकतम करती है
  • Web Streams के साथ interoperability के लिए सरल adapter functions से conversion संभव है

प्रदर्शन तुलना और आगे की दिशा

  • Node.js benchmarks में अधिकतम 80~90 गुना, और ब्राउज़र में 100 गुना से अधिक तेज processing speed देखी गई
    • उदाहरण: 3-stage transformation chain में 275GB/s बनाम 3GB/s
  • performance gains का कारण async overhead हटाना, batch processing, और pull-based design है
  • यह implementation pure TypeScript/JavaScript में लिखी गई है, और native implementation पर अतिरिक्त सुधार की संभावना है
  • Cloudflare इस approach को standards discussion के शुरुआती बिंदु के रूप में पेश कर रहा है और developer community से feedback मांग रहा है

निष्कर्ष

  • Web Streams अपने समय की सीमाओं में व्यावहारिक थे, लेकिन आधुनिक JavaScript की language features और development patterns के अनुरूप नहीं हैं
  • नया async iterable-आधारित model सरलता, performance, और स्पष्ट नियंत्रण तीनों को पूरा करता है, और runtimes के बीच एकसमान streaming ecosystem की संभावना दिखाता है
  • Cloudflare ने GitHub के jasnell/new-streams पर reference implementation, documentation, और example code प्रकाशित किए हैं
  • लक्ष्य नया मानक बनाना नहीं, बल्कि “बेहतर stream API” पर चर्चा शुरू करने के लिए एक व्यावहारिक शुरुआती बिंदु तैयार करना है

1 टिप्पणियां

 
GN⁺ 2026-02-28
Hacker News की राय
  • मैंने इस लेख में प्रस्तावित API से बेहतर Stream interface खुद डिज़ाइन किया है
    मौजूदा प्रस्ताव async iterator of UInt8Array के रूप में है, लेकिन मैंने ऐसी संरचना प्रस्तावित की है जिसमें next() synchronous या asynchronous दोनों तरह के परिणाम लौटा सकता है
    इससे
    मौजूदा संरचना की तुलना में एक ही iterator से सरल iteration संभव हो जाता है
    synchronous input पर synchronous transformation लागू करने से पूरा processing synchronous रूप से हो सकता है, जिससे code duplication कम होती है
    अनावश्यक Promise creation कम होने से performance बेहतर होती है
    concurrency control संभव हो जाता है, जिससे async iterator की सीमाओं को पार किया जा सकता है

    • तुम कह रहे हो कि तुम्हारा प्रस्तावित तरीका बेहतर है, लेकिन वास्तव में मुझे लगता है कि सामने वाले का तरीका एक अधिक मौलिक primitive form के रूप में बेहतर है
      तुम्हारे तरीके से उनकी संरचना आसानी से नहीं बनाई जा सकती, जबकि उल्टा संभव है
      I/O-केंद्रित iterator को T इकाई के chunks लौटाने चाहिए ताकि buffer waste रोका जा सके
    • प्रस्तावित stream concept दिलचस्प है, लेकिन उनकी design AsyncIterator compatibility को आधार मानती है
      Uint8Array का उपयोग OS-स्तर के byte stream के साथ मेल बैठाने के लिए किया जाता है
      वास्तव में C-आधारित projects में भी ऐसी संरचना सबसे efficient होती है, इसलिए type information वाले protocol का उसके ऊपर बनना स्वाभाविक है
    • Node 24 में synchronous function call और async function call की speed difference को microbenchmark से मापा गया, और यह लगभग 90 गुना धीमा था
      पुराने versions में यह अंतर 105 गुना तक था
      async processing optimization Node 16 में हुई थी, और याद है कि उस समय कुछ tests टूट गए थे
    • Uint8Array नाम का कोई type मौजूद नहीं है
      Uint8Array सिर्फ byte array को दर्शाने वाला primitive type है, और type information को protocol नहीं बल्कि application level पर संभालना चाहिए
    • यह संरचना Clojure के transducer concept जैसी है
      संदर्भ: Clojure Transducers दस्तावेज़
  • Async iterable भी पूरी तरह का समाधान नहीं है
    Promise और stack switching overhead बड़ा है, इसलिए छोटे unit के data को संभालते समय performance खराब होती है
    Lit-SSR ने इसे हल करने के लिए synchronous iterable के अंदर thunk शामिल करने का तरीका इस्तेमाल किया
    केवल तब thunk को call और await किया जाता है जब async work की ज़रूरत हो, और इससे SSR performance 12~18 गुना बेहतर हुई
    लेकिन Streams API के लिए ऐसा नाज़ुक contract structure अपनाना मुश्किल है, इसलिए write() और writeAsync() जैसी optional async processing वाली संरचना आदर्श लगती है

    • तुमने जो समस्या बताई, उसे मेरा stream iterator हल कर सकता है
      synchronous generator का उपयोग करने वाला उदाहरण मैंने GitHub code में साझा किया है
      मुख्य बिंदु step.value.then(value => this.next(value)) वाला हिस्सा है
    • मुझे conartist6 का प्रस्ताव (next(): {done, value: T} | Promise) पसंद आया
      2013 की “Do not unleash Zalgo” बहस के बाद MaybeAsync रूप से बचने की प्रवृत्ति रही है, लेकिन
      मुझे लगता है कि इस डर को बहुत बढ़ा-चढ़ाकर देखा गया है और यह तेज़ और लचीले API design को रोक रहा है
      एक बार में कई values खींचने वाली utility भी बनाई जा सकती है, और generator speed की समस्या व्यवहार में उतनी बड़ी नहीं लगती
  • Node.js में Web Streams को संभालना बहुत कष्टदायक है
    यह browser-केंद्रित design है, इसलिए server environment में असुविधाजनक है
    साधारण transformation के लिए भी transform stream को wrap करना पड़ता है, और .pipe() जैसी intuitive chaining कठिन है
    Async iterable approach कहीं अधिक natural है और for-await-of के साथ अच्छी तरह मेल खाती है
    Web Streams spec बहुत अधिक abstraction-केंद्रित है, इसलिए इसकी practicality कम हो जाती है

    • यह जानकर हैरानी हुई कि Node में लोग वास्तव में Web Streams इस्तेमाल करते हैं
      मुझे लगा था कि वह सिर्फ client–server compatibility के लिए है
  • असली फ़ायदा सिर्फ performance नहीं बल्कि environments के बीच consistency (convergence) है
    अगर ReadableStream browser, Worker और दूसरे runtimes में एक जैसा काम करे
    तो code portability और backpressure bugs में कमी का बड़ा लाभ मिलता है
    stream layer का standardization भरोसेमंद streaming systems बनाने की कुंजी है

    • सही कहा, यह सिर्फ performance नहीं बल्कि standardization की value है
  • मैंने पहले Repeater नाम का abstraction बनाया था
    यह Promise constructor को async iterable में ले जाने जैसा concept है, जहाँ events को push/stop से नियंत्रित किया जाता है
    Repeater library हफ़्ते में 65 लाख downloads दर्ज करने जितनी stable है
    हाल में मुझे streams ज़्यादा पसंद हैं, लेकिन tee() से जुड़ी आलोचना अब भी वैध है
    मुझे लगता है कि async iterable को मूल abstraction मानने की दिशा सही है

    • Repeater में stop का function और Promise दोनों की तरह काम करना दिलचस्प लगा
      source code देखने के बाद
      यह पारंपरिक pattern से अलग है, लेकिन लगा कि यह ergonomic design के लिए किया गया जानबूझकर चुनाव हो सकता है
    • विषय से अलग, लेकिन Konami code का उदाहरण देखकर बहुत अच्छा लगा
      nostalgia इतनी गहरी है कि मैं email signature में भी “Up, Up, Down, Down, Left, Right, Left, Right, B, A” लिखता हूँ
  • मैंने भी AsyncIterable को अधिक संक्षेप में इस्तेमाल करने के लिए wrapper बनाया था
    वह fluent-async-iterator है,
    और Lambda या CLI pipelines में छोटे पैमाने की data streaming के लिए उपयोगी था
    उम्मीद थी कि अब तक कोई बेहतर API आ गई होगी

  • ReadableStream.tee() का backpressure behavior Node.js के pipe() के उलट होने से भ्रम पैदा होता है
    specification में लिखा है कि “सबसे धीमा output गति तय करे”, लेकिन वास्तविक implementation में तेज़ वाला side consume न हो तब भी रुकावट आती है
    नए Stream API जैसी push-आधारित संक्षिप्त संरचना बेहतर लगती है
    Node और Web Streams infinite queue रखकर synchronous रूप से res.write() की बौछार की अनुमति देते हैं, लेकिन
    यह API generator-आधारित yield flow को अनिवार्य बनाती है, इसलिए अधिक सुरक्षित है

  • Node.js में undici(fetch) इस्तेमाल करते समय connection pool exhaustion की समस्या
    garbage collection language की सीमा की वजह से होती है
    अगर resources को explicitly बंद न किया जाए, तो GC timing के अनुसार leak हो सकता है
    C++ का RAII(reference counting) approach उलटे अधिक सुरक्षित है

  • resource cleanup के मामले में उम्मीद है कि using/await using pattern धीरे-धीरे और फैले
    C# के using की तरह dispose/disposeAsync को support करने वाली संरचना को DB drivers में लागू किया जा रहा है

  • benchmark numbers (जैसे 530GB/s) M1 Pro की memory bandwidth (200GB/s) से अधिक हैं, इसलिए उन पर भरोसा करना कठिन है
    संभव है कि यह implementation quality control की कमी वाला vibe-coded benchmark हो