_transform और _flush से कस्टम ट्रांसफ़ॉर्म स्ट्रीम लागू करना
ऐसी पुनःप्रयोग योग्य Transform स्ट्रीम बनाइए, जो डेटा के प्रवाह के दौरान खंडों को बदलें, फ़िल्टर करें और एकत्र करें।
_transform और _flush से कस्टम ट्रांसफ़ॉर्म स्ट्रीम लागू करना, CoddyKit पर Node.js बैकएंड विकास बूटकैंप का एक निःशुल्क पाठ है। यह 4 में से 2वाँ पाठ है। आप नीचे पूरा पाठ निःशुल्क पढ़ सकते हैं—फिर अंतर्निहित कोड संपादक और 24/7 एआई ट्यूटर के साथ ब्राउज़र में इसका व्यावहारिक अभ्यास कर सकते हैं। यह Node.js बैकएंड विकास बूटकैंप सीखने के मार्ग का हिस्सा है और आपकी प्रगति वेब तथा CoddyKit ऐप पर सिंक होती रहती है। Node.js बैकएंड विकास बूटकैंप पाठ्यक्रम में कुल 4 पाठ शामिल हैं।
रूपांतरण स्ट्रीम क्यों?
रूपांतरण स्ट्रीम पढ़ने योग्य और लिखने योग्य, दोनों होती है: यह इनपुट के हिस्से लेती है, उन्हें संसाधित करती है और आउटपुट के हिस्से भेजती है। जब डेटा को पूरी तरह मेमोरी में बफ़र करने के बजाय प्रवाह के दौरान बदलना हो, तब यही सही साधन है।
- लिखने योग्य पक्ष ऊपर की स्ट्रीम से
write()/pipe()के माध्यम से डेटा स्वीकार करता है। - पढ़ने योग्य पक्ष संसाधित डेटा उपलब्ध कराता है, जिसे नीचे के उपभोक्ता पढ़ते हैं।
बैकएंड में इसके सामान्य उपयोग हैं: पेलोड को बड़े अक्षरों में बदलना या सामान्यीकृत करना, gzip जैसी एन्कोडिंग, CSV को JSON में बदलना, लॉग प्रवाह में गुप्त जानकारी हटाना या बाइट गिनना — और यह सब पूरी फ़ाइल या HTTP बॉडी को RAM में लोड किए बिना।
दो हुक: _transform और _flush
कस्टम रूपांतरण स्ट्रीम को दो आंतरिक विधियाँ लागू करके परिभाषित किया जाता है। Node इन्हें आपके लिए कॉल करता है — आपको इन्हें सीधे कभी कॉल नहीं करना चाहिए।
_transform(chunk, encoding, callback)— आने वाले प्रत्येक हिस्से के लिए एक बार चलाया जाता है। अपना काम करें, कोई भी आउटपुटpush()करें, फिरcallback()से पूर्णता का संकेत दें।_flush(callback)— अंतिम हिस्से के बाद, स्ट्रीम समाप्त होने से ठीक पहले एक बार चलाया जाता है। बचे हुए या एकत्रित डेटा को भेजने के लिए इसका उपयोग करें।
शुरुआती अंडरस्कोर यह दर्शाता है कि ये फ़्रेमवर्क के लिए लागू की जाने वाली विधियाँ हैं। उपभोक्ता अब भी सार्वजनिक write, read और pipe API का उपयोग करते हैं।
एक न्यूनतम बड़े-अक्षर रूपांतरण
शुरू करने का पारंपरिक तरीका: Transform क्लास का विस्तार करें और _transform को अधिलेखित करें। प्रत्येक हिस्सा एक Buffer होता है (जब तक ऑब्जेक्ट मोड न हो), इसलिए उसे स्ट्रिंग में बदलें, उसका रूपांतरण करें और परिणाम को push करें।
बिना त्रुटि के callback() कॉल करने से Node को पता चलता है कि यह हिस्सा पूरी तरह संसाधित हो चुका है और वह अगला हिस्सा भेज सकता है। मान को callback के दूसरे तर्क के रूप में देना, push + callback() का संक्षिप्त रूप है।
const { Transform } = require('node:stream');
class Upper extends Transform {
_transform(chunk, encoding, callback) {
const out = chunk.toString().toUpperCase();
callback(null, out); // shorthand for this.push(out); callback();
}
}
const up = new Upper();
up.on('data', (d) => process.stdout.write(d));
up.write('hello ');
up.write('streams\n');
up.end();callback() एक अनुबंध है
_transform में callback अनिवार्य है। जब तक आप इसे कॉल नहीं करते, Node मानता है कि हिस्सा अभी संसाधित हो रहा है और आपको अगला हिस्सा नहीं देगा। इसी तरह बैकप्रेशर आपके रूपांतरण में आगे बढ़ता है।
callback()— सफलता, अगले हिस्से के लिए तैयार।callback(err)—'error'इवेंट भेजता है और स्ट्रीम नष्ट कर देता है।callback(null, data)—dataभेजता है और सफलता का संकेत देता है।
callback कॉल करना भूल जाना सबसे आम बग है: बिना किसी त्रुटि के पूरा प्रवाह चुपचाप हमेशा के लिए रुक जाता है।
प्रति हिस्से कई बार push()
एक इनपुट हिस्सा शून्य, एक या कई आउटपुट हिस्से बना सकता है। callback() कॉल करने से पहले जितनी बार आवश्यक हो, this.push() कॉल करें। इसी से हिस्सों को विभाजित करना (जैसे पंक्ति-दर-पंक्ति) संभव होता है।
नीचे, कई पंक्तियों वाली एकल write को हर पंक्ति के लिए एक push में बाँटा गया है।
const { Transform } = require('node:stream');
class LineSplitter extends Transform {
_transform(chunk, encoding, callback) {
const lines = chunk.toString().split('\n');
for (const line of lines) {
if (line.length) this.push(line + ' <<\n');
}
callback();
}
}
const s = new LineSplitter();
s.on('data', (d) => process.stdout.write(d));
s.end('alpha\nbeta\ngamma\n');फ़िल्टर करना: कुछ भी न भेजकर हिस्से हटाना
फ़िल्टर करने के लिए बस यह तय करें कि push नहीं करना है। यदि किसी हिस्से को हटाना हो, तो कुछ भी भेजे बिना callback() कॉल करें — डेटा पढ़ने योग्य पक्ष तक कभी नहीं पहुँचता।
यह तरीका प्रवाह के बीच रिकॉर्ड से गुप्त जानकारी हटाने या रिकॉर्ड छोड़ने के लिए आदर्श है, जैसे किसी गुप्त टोकन वाली लॉग पंक्तियों को हटाना।
const { Transform } = require('node:stream');
class DropSecrets extends Transform {
_transform(chunk, encoding, callback) {
const line = chunk.toString();
if (line.includes('SECRET')) {
return callback(); // filtered out, nothing pushed
}
callback(null, line);
}
}
const f = new DropSecrets();
f.on('data', (d) => process.stdout.write(d));
f.write('ok line 1\n');
f.write('this has a SECRET token\n');
f.write('ok line 2\n');
f.end();संरचित रिकॉर्ड के लिए ऑब्जेक्ट मोड
डिफ़ॉल्ट रूप से हिस्से Buffer/स्ट्रिंग होते हैं। इसके बजाय JavaScript ऑब्जेक्ट भेजने और प्राप्त करने के लिए objectMode: true सेट करें — रिकॉर्ड-आधारित प्रवाहों (JSON पंक्तियाँ, डेटाबेस परिणाम, पार्स किए गए इवेंट) के लिए यह आवश्यक है।
- यदि इनपुट और आउटपुट के प्रकार अलग हों, तो
writableObjectMode/readableObjectModeको स्वतंत्र रूप से सेट किया जा सकता है। - ऑब्जेक्ट मोड में, प्रत्येक
pushआकार की परवाह किए बिना ठीक एक ऑब्जेक्ट भेजता है।
const { Transform } = require('node:stream');
class AddTax extends Transform {
constructor() { super({ objectMode: true }); }
_transform(order, encoding, callback) {
callback(null, { ...order, total: order.price * 1.2 });
}
}
const t = new AddTax();
t.on('data', (o) => console.log(o));
t.write({ id: 1, price: 100 });
t.write({ id: 2, price: 250 });
t.end();_flush: बचा हुआ या एकत्रित डेटा भेजना
_flush(callback) अंतिम हिस्से के बाद और 'end' से पहले एक बार चलता है। आपने जो कुछ जमा किया है — जैसे चलता हुआ कुल, बफ़र की गई अधूरी पंक्ति या समापन सीमांकक — उसे भेजने का स्थान यही है।
आप _transform की तरह _flush के भीतर push कर सकते हैं। स्ट्रीम को समाप्त होने देने के लिए आपको इसका callback() अवश्य कॉल करना होगा।
const { Transform } = require('node:stream');
class Summer extends Transform {
constructor() { super({ objectMode: true }); this.sum = 0; }
_transform(num, encoding, callback) {
this.sum += num;
callback(); // aggregate, emit nothing yet
}
_flush(callback) {
this.push({ total: this.sum }); // emit once at the end
callback();
}
}
const agg = new Summer();
agg.on('data', (o) => console.log(o));
[10, 20, 30, 40].forEach((n) => agg.write(n));
agg.end();हिस्सों की सीमाओं के बीच अधूरी पंक्तियों को बफ़र करना
हिस्से तार्किक रिकॉर्ड के अनुरूप नहीं होते। कोई पंक्ति दो हिस्सों में विभाजित हो सकती है, इसलिए एक मज़बूत पंक्ति-पार्सर कॉल के बीच बचा हुआ बफ़र रखता है और _flush में शेष डेटा भेजता है।
_transform में जोड़ना और _flush में निकालना वाला यह तरीका वास्तविक CSV/NDJSON पार्सरों की आधारशिला है।
const { Transform } = require('node:stream');
class LineParser extends Transform {
constructor() { super({ readableObjectMode: true }); this.tail = ''; }
_transform(chunk, encoding, callback) {
const data = this.tail + chunk.toString();
const parts = data.split('\n');
this.tail = parts.pop(); // keep incomplete last segment
for (const line of parts) this.push(line);
callback();
}
_flush(callback) {
if (this.tail) this.push(this.tail);
callback();
}
}
const p = new LineParser();
p.on('data', (l) => console.log('LINE:', l));
p.write('he');
p.write('llo\nwor');
p.write('ld\nlast');
p.end();कार्यात्मक संक्षिप्त रूप: stream.Transform विकल्प
आपको हमेशा क्लास की आवश्यकता नहीं होती। Transform कंस्ट्रक्टर सीधे transform और flush फ़ंक्शन स्वीकार करता है — छोटे, एक-बार इस्तेमाल होने वाले रूपांतरणों के लिए यह सुविधाजनक है।
इन फ़ंक्शन के भीतर this अब भी स्ट्रीम ही होता है, इसलिए this.push() काम करता है। जब आपको पुनः उपयोग योग्य, नामित और इंस्टैंशिएट किए जा सकने वाले घटक चाहिए हों, तब क्लास वाला रूप बेहतर है; त्वरित जोड़-तोड़ के लिए इनलाइन रूप उपयोगी है।
const { Transform } = require('node:stream');
const csvToRows = new Transform({
readableObjectMode: true,
transform(chunk, encoding, callback) {
for (const line of chunk.toString().trim().split('\n')) {
const [id, name] = line.split(',');
this.push({ id: Number(id), name });
}
callback();
},
});
csvToRows.on('data', (row) => console.log(row));
csvToRows.end('1,Ada\n2,Linus\n3,Grace');प्रवाह में संयोजन
रूपांतरण स्ट्रीम को श्रृंखला में जोड़ने पर उनका प्रभाव सबसे अच्छा दिखता है। सामान्य .pipe() के बजाय stream.pipeline() (कॉलबैक या प्रॉमिस रूप) का उपयोग करें — यह त्रुटियाँ आगे भेजता है और विफलता पर हर स्ट्रीम को नष्ट करता है, जिससे रिसाव रुकते हैं।
यहाँ एक स्रोत पहले बड़े-अक्षर रूपांतरक, फिर प्रत्यय जोड़ने वाले रूपांतरक और अंत में stdout को डेटा देता है। प्रत्येक रूपांतरण छोटा और पुनः उपयोग योग्य रहता है।
const { Transform, Readable, pipeline } = require('node:stream');
const make = (fn) => new Transform({
transform(chunk, enc, cb) { cb(null, fn(chunk.toString())); },
});
const upper = make((s) => s.toUpperCase());
const bang = make((s) => s + '!\n');
pipeline(
Readable.from(['log a\n', 'log b\n']),
upper,
bang,
process.stdout,
(err) => { if (err) console.error('failed', err); else console.error('done'); }
);त्वरित जाँच: अंत में एकत्रित डेटा कहाँ जाता है?
आप ऐसी रूपांतरण स्ट्रीम बना रहे हैं जो देखे गए कुल बाइट गिनती है और समस्त इनपुट संसाधित होने के बाद एक सारांश ऑब्जेक्ट भेजनी है। उस सारांश को किस विधि को भेजना चाहिए?
पुनरावलोकन: रूपांतरण स्ट्रीम की आवश्यक बातें
अब आप ऐसी पुनः उपयोग योग्य रूपांतरण स्ट्रीम बना सकते हैं जो प्रवाहित डेटा को बदलती, फ़िल्टर करती और एकत्रित करती हैं:
- _transform(chunk, enc, cb) — प्रत्येक हिस्से को संसाधित करें; शून्य या अधिक आउटपुट
pushकरें; हमेशाcb()(याcb(null, data)) कॉल करें। - _flush(cb) — अंत में एक बार चलता है और बचा हुआ या एकत्रित डेटा भेजता है;
cb()कॉल करना आवश्यक है। - कुछ भी न भेजकर फ़िल्टर करें; कई बार भेजकर विभाजित करें; स्थिति जमा करके और अंत में भेजकर एकत्रित करें।
- objectMode (और इसके स्वतंत्र पढ़ने योग्य/लिखने योग्य रूप) संरचित रिकॉर्ड ले जाता है।
- अधूरे रिकॉर्ड
_transformमें बफ़र करें और उन्हें_flushमें निकालें। - सुरक्षित त्रुटि प्रबंधन और सफ़ाई के लिए
stream.pipeline()से संयोजन करें।
कॉलबैक को कभी न भूलें — cb() न होने पर पूरा प्रवाह चुपचाप रुक जाता है।
एआई शिक्षक के साथ JavaScript सीखें — निःशुल्क
अपने ब्राउज़र में वास्तविक कोड लिखें और चलाएँ, चौबीसों घंटे एआई शिक्षक से तुरंत सहायता पाएँ, और वेब या ऐप पर वहीं से शुरू करें जहाँ आपने छोड़ा था।
- पाठ्यक्रम
- 22
- पाठ
- 92
अक्सर पूछे जाने वाले प्रश्न
क्या “_transform और _flush से कस्टम ट्रांसफ़ॉर्म स्ट्रीम लागू करना” पाठ निःशुल्क है?
हाँ—“_transform और _flush से कस्टम ट्रांसफ़ॉर्म स्ट्रीम लागू करना” का पूरा पाठ यहाँ वेब पर निःशुल्क पढ़ा जा सकता है। इंटरैक्टिव अभ्यास (अंतर्निहित कोड संपादक और 24/7 एआई ट्यूटर) करने और Node.js बैकएंड विकास बूटकैंप पाठ्यक्रम का बाकी हिस्सा अनलॉक करने के लिए CoddyKit PRO लें। Node.js बैकएंड विकास बूटकैंप पाठ्यक्रम में कुल 4 पाठ शामिल हैं।
“_transform और _flush से कस्टम ट्रांसफ़ॉर्म स्ट्रीम लागू करना” में मैं क्या सीखूँगा?
ऐसी पुनःप्रयोग योग्य Transform स्ट्रीम बनाइए, जो डेटा के प्रवाह के दौरान खंडों को बदलें, फ़िल्टर करें और एकत्र करें। आप ब्राउज़र में सीधे चलाए जाने वाले व्यावहारिक कोड के साथ Node.js बैकएंड विकास बूटकैंप का अभ्यास करते हैं, और पाठ पूरा करते समय 24/7 एआई ट्यूटर आपके प्रश्नों के उत्तर देता है।
क्या Node.js बैकएंड विकास बूटकैंप शुरू करने के लिए मुझे किसी अनुभव की आवश्यकता है?
पहले के अनुभव की आवश्यकता नहीं है। CoddyKit पर Node.js बैकएंड विकास बूटकैंप शुरुआती से लेकर उन्नत शिक्षार्थियों तक सभी के लिए व्यवस्थित किया गया है, इसलिए आप यहीं से या शुरुआत से सीखना शुरू कर सकते हैं और अपनी गति से आगे बढ़ सकते हैं। यह 4 में से 2वाँ पाठ है।
“_transform और _flush से कस्टम ट्रांसफ़ॉर्म स्ट्रीम लागू करना” पाठ पूरा करने में कितना समय लगता है?
CoddyKit का अधिकांश पाठ लगभग 5–10 मिनट में पूरा हो जाता है। हर पाठ छोटा और संवादात्मक है, इसलिए आप लगातार प्रगति करते हैं और वेब या ऐप पर वहीं से सीखना जारी रख सकते हैं जहाँ आपने छोड़ा था।
क्या मैं इस Node.js बैकएंड विकास बूटकैंप पाठ में कोड लिख और चला सकता हूँ?
हाँ। हर Node.js बैकएंड विकास बूटकैंप पाठ में एक अंतर्निर्मित कोड संपादक शामिल है, जिससे आप सीधे अपने ब्राउज़र में वास्तविक कोड लिख और चला सकते हैं और तुरंत एआई प्रतिक्रिया पा सकते हैं—स्थानीय सेटअप की आवश्यकता नहीं है।
इस पाठ्यक्रम के सभी पाठ
- पठनीय, लेखनीय, द्विदिश और ट्रांसफ़ॉर्म स्ट्रीम के आंतरिक तंत्र
- _transform और _flush से कस्टम ट्रांसफ़ॉर्म स्ट्रीम लागू करना
- बैकप्रेशर, pipe() और pipeline() यूटिलिटी
- स्ट्रीम पर Async इटरेटर और for-await-of