از طریق منوی جستجو مطلب مورد نظر خود در وبلاگ را به سرعت پیدا کنید
مقدمه Node.js StreamsStreams یک مفهوم تا حدی پیشرفته برای درک است. بنابراین در این مقاله برای درک بهتر چند مثال را همراهی می کنیم و شما را با چند مفهوم در این مسیر آشنا می کنیم. جریان چیست به زبان ساده، جریان ها برای خواندن از ورودی یا نوشتن به…
سرفصلهای مطلب
معرفی
جریان ها یک مفهوم تا حدودی پیشرفته برای درک هستند. بنابراین در این مقاله برای درک بهتر چند مثال را همراهی می کنیم و شما را با چند مفهوم در این مسیر آشنا می کنیم.
استریم چیست
به عبارت ساده تر، جریان ها برای خواندن از ورودی یا نوشتن به خروجی به صورت متوالی استفاده می شوند. بیشتر اوقات، جریان ها برای خواندن یا نوشتن از یک منبع پیوسته یا یک منبع نسبتاً بزرگ استفاده می شوند.
به عنوان مثال، فرض کنید باید یک فایل بزرگ را بخوانید. اگر اندازه فایل بزرگتر از فضای حافظه آزاد شما باشد، نمی توانید کل فایل را در حافظه بخوانید تا بتوانید process آی تی. باید قطعه قطعه بخوانی و process هر تکه، که ممکن است برای مثال با یک خط از هم جدا شود.
مثال دیگری از یک منبع پیوسته ارتباطات شبکه است – مانند یک برنامه چت که در آن داده ها باید به طور مداوم از فرستنده به گیرنده در جریان باشد.
جریان در Node.js
را Stream
module یک ماژول بومی است که به طور پیش فرض در Node.js ارسال می شود. را Stream
نمونه ای از Event Emitter کلاس، که رویدادها را به صورت ناهمزمان در Node.js مدیریت می کند. به دلیل سوپرکلاسی که دارند، جریان ها ذاتاً مبتنی بر رویداد هستند.
4 نوع استریم در Node.js وجود دارد:
- قابل نوشتن: برای نوشتن داده ها به صورت متوالی استفاده می شود
- قابل خواندن: برای خواندن متوالی داده ها استفاده می شود
- دوبلکس: برای خواندن و نوشتن متوالی داده ها استفاده می شود
- تبدیل: جایی که می توان داده ها را هنگام نوشتن یا خواندن تغییر داد. به عنوان مثال فشرده سازی را در نظر بگیرید، با جریانی مانند این می توانید داده های فشرده شده را بنویسید و داده های فشرده شده را بخوانید.
بیایید به چند نمونه از استریم ها نگاهی بیندازیم.
جریان های قابل نوشتن
اول از همه، اجازه دهید یک جریان قابل نوشتن ایجاد کنیم و برخی از داده ها را در یک فایل بنویسیم:
const fs = require('fs');
const file = fs.createWriteStream('file.txt');
file.write('hello world');
file.end(', from streams!');
در این کد، ما از ماژول سیستم فایل برای ایجاد یک جریان قابل نوشتن به یک فایل (file.txt
) و 2 تکه جداگانه روی آن بنویسید: hello world
و , from streams
.
بر خلاف fs.writeFile()
جایی که باید محتوای فایل را یکباره بنویسیم، با استفاده از یک جریان میتوانیم محتوا را تکه به تکه بنویسیم.
برای شبیهسازی یک ورودی پیوسته، میتوانیم کاری را در امتداد خطوط زیر انجام دهیم:
const fs = require('fs');
const file = fs.createWriteStream('file.txt');
for (let i = 0; i < 10000; i++) {
file.write('Hello world ' + i);
}
file.end();
این خواهد نوشت Hello world + {i}
ده هزار بار و سپس جریان را تمام کنید:
Hello world 0
Hello world 1
Hello world 2
Hello world 3
Hello world 4
...
لطفا به یاد داشته باشید .end()
استریم های خود را پس از اتمام استفاده از آنها، از آنجایی که finish
رویداد پس از ارسال ارسال می شود .end()
روش نامیده شده است.
این نشان می دهد که بدنه جریان در پرونده ما ریخته شده است.
جریان های خواندنی
حالا بیایید با خواندن یک فایل با استفاده از جریان، به مثال ساده دیگری نگاهی بیندازیم. میتوانیم یک فایل را تکه تکه بخوانیم، بهجای خواندن محتوای کامل در حافظه، با استفاده از یک جریان قابل خواندن:
const fs = require('fs');
const readableStream = fs.createReadStream('./article.md', {
highWaterMark: 10
});
readableStream.روی('readable', () => {
process.stdout.write(`(${readableStream.read()})`);
});
readableStream.روی('end', () => {
console.log('DONE');
});
مشابه ایجاد یک جریان قابل نوشتن، با فراخوانی یک جریان قابل خواندن ایجاد کرده ایم .createReadStream()
روش.
در حین بافر (بخش بندی داده ها به قطعات)، اندازه بافر بستگی دارد روی را highWaterMark
پارامتر، که به سازنده جریان ارسال می شود.
مقدار پیشفرض این پارامتر 16384 بایت (16 کیلوبایت) است، بنابراین اگر پارامتر را لغو نکنید، جریان تکههای 16 کیلوبایتی را میخواند و به شما ارسال میکند تا process.
از آنجایی که ما از یک فایل متنی کوچک استفاده می کنیم، منطقی تر است که از یک مقدار کوچک برای مثال خود استفاده کنیم، بنابراین متن با 10 کاراکتر کوچک می شود.
در مثال بالا، ما به سادگی تکهای از دادههایی را که دریافت کردهایم، بهجز با براکتهایی در اطراف آن چاپ کردیم تا بتوانید تکههای مختلف را به راحتی ببینید. خروجی کد ما به شکل زیر است:
(### Introd)(uction
St)(reams are )(a somewhat)( advanced )(concept to)( understan)(d. So in t)(his articl)(e, we will)( go along )(with some )(examples f)(or a bette)(r understa)(nding and )(introduce )(you to a f)(ew concept)(s along th)(e way.
##)(# What is )(a Stream
)(In simple )...
جریان های دوبلکس
با وجود هر دو جریان قابل نوشتن و خواندن خارج از مسیر، میتوانیم با استفاده از جریانهای دوبلکس به یک مثال بپردازیم – که اساساً هر دو را با هم ترکیب میکنند.
ما آنها را با استفاده از یک سرور HTTP ساده که با استفاده از Node.js بومی ساخته شده است، نشان خواهیم داد http
مدول. مثال استفاده شده در اینجا از مقام رسمی است مستندات Node.js.
از آنجایی که سرورها درخواستها را دریافت میکنند و سپس پاسخها را ارسال میکنند، آنها نمونه خوبی برای جریانهای دوبلکس هستند که هر دو را مدیریت میکنند – یک جریان قابل خواندن به عنوان یک درخواست پیوسته و یک جریان قابل نوشتن به عنوان یک پاسخ عمل میکند.
اول، اجازه دهید import ماژول HTTP:
const http = require('http');
حالا بیایید یک سرور HTTP ساده ایجاد کنیم:
const server = http.createServer((req, res) => {
// `req` is an http.IncomingMessage, which is a Readable Stream.
// `res` is an http.ServerResponse, which is a Writable Stream.
let body = '';
// Get the data as utf8 strings.
// If an encoding is not set, Buffer objects will be received.
req.setEncoding('utf8');
// Readable streams emit 'data' events once a listener is added.
req.روی('data', (chunk) => {
body += chunk;
});
// The 'end' event indicates that the entire body has been received.
req.روی('end', () => {
consol.log(body);
try {
// Send 'Hello World' to the user
res.write('Hello World');
res.end();
} catch (er) {
res.statusCode = 400;
return res.end(`error: ${er.message}`);
}
});
});
را req
پارامتر یک جریان قابل خواندن است که ما آن را انجام خواهیم داد process پس از دریافت به عنوان یک درخواست HTTP. سپس ارسال می کنیم res
به عنوان یک پاسخ، که باز هم یک جریان ساده قابل نوشتن است.
سپس با استفاده از .روی()
به روش، بدنه درخواست را در تکه های 64 کیلوبایت می خوانیم و آن را در آن ذخیره می کنیم body
ایجاد شده توسط data
رویداد.
لطفا به استفاده از setEncoding()
روش قبل از خواندن از جریان
به این ترتیب، جریان رشته ها را منتشر می کند و منتشر می کند Buffer
اشیاء در غیر این صورت. با این حال، می توانید آن مکالمه را در داخل نیز انجام دهید data
در صورت تمایل، تماس مجدد رویداد
را end
رویداد زمانی فعال می شود که چیزی برای خواندن در یک جریان قابل خواندن باقی نمانده باشد. در ادامه این مقاله در مورد سایر رویدادهای مفید صحبت خواهیم کرد.
حالا بیایید به سرور گوش کنیم:
server.listen(1337);
ضربه زدن http://localhost:1337
، شما باید یک ساده ببینید Hello World
پاسخ از سرور HTTP
خطوط لوله جریان
با استفاده از لولههای جریان، میتوانیم مستقیماً جریانهای قابل خواندن را بدون ذخیره موقت بافر به یک جریان قابل نوشتن انتقال دهیم – بنابراین میتوانیم فضای حافظه را ذخیره کنیم.
سناریویی را در نظر بگیرید که در آن کاربر یک فایل بزرگ از سرور درخواست می کند و فضای حافظه ای برای بارگذاری آن در حافظه وجود ندارد یا همان فایل توسط هزار مشتری مختلف درخواست می شود. در این حالت، نمیتوانیم محتوای فایل را روی حافظه بخوانیم و سپس آن را برای مشتری بنویسیم.
اینجاست که pipe
روش مفید است، زیرا ما یک جریان قابل خواندن (یک درخواست) را به یک جریان قابل نوشتن (یک پاسخ) لوله می کنیم و بدون نگه داشتن آن در بافر به کاربر ارائه می کنیم.
ابتدا بیایید این کار را بدون استفاده از جریان ها انجام دهیم:
const fs = require('fs');
const server = require('http').createServer();
server.روی('request', (req, res) => {
fs.readFile('./video.mkv', (err, data) => {
if (err) throw err;
res.end(data);
});
});
server.listen(1337);
این روش مستقیماً فایل را در حافظه با استفاده از .readFile()
روش و برای کاربر ارسال می کند.
مرورگر وب خود را باز کنید و به http://localhost:1337
، این چیزی است که در پشت صحنه اتفاق می افتد:
اکنون، بیایید ویدیو را با استفاده از یک جریان ارائه کنیم:
const http = require('http');
const fs = require('fs');
const server = http.createServer((req, res) => {
const src = fs.createReadStream('./video.mkv');
src.pipe(res);
});
server.listen(1337);
در این کد، یک جریان قابل خواندن برای فایل ایجاد کرده ایم و مستقیماً آن را به پاسخ HTTP لوله می کنیم، بنابراین به جای بارگذاری آن در حافظه، ورودی هارد دیسک مستقیماً بدون مصرف حافظه در شبکه نوشته می شود.
در اینجا اسکرین شات استفاده از حافظه هنگام ارسال فایل با استفاده از جریان است:
همانطور که می بینید استفاده از حافظه در مقایسه با روش اول بسیار کم است.
رویدادهای مفید در یک جریان
از آنجا که Stream
کلاس به ارث می برد EventEmitter
کلاس، هر جریان نوع رویدادهای خاص خود را خواهد داشت که می توانید با استفاده از آنها مشترک شوید EventEmitter
‘s روی()
روش. این رویداد بستگی دارد روی نوع جریان
رویدادها در جریانهای خواندنی
data
: هنگامی که یک تکه داده از جریان خوانده می شود، منتشر می شود. به طور پیش فرض، تکه یک خواهد بودBuffer
هدف – شی. اگر می خواهید آن را تغییر دهید می توانید از آن استفاده کنید.setEncoding()
روش.error
: هنگامی که خطایی در هنگام خواندن رخ می دهد منتشر می شود. این ممکن است در صورتی اتفاق بیفتد که جریان قابل نوشتن به دلیل نقص داخلی نتواند داده تولید کند یا زمانی که یک قطعه نامعتبر به جریان فشار داده شود.end
: زمانی که داده دیگری در جریان وجود ندارد، منتشر می شود.close
: هنگامی که منبع جریان بسته است منتشر می شود و نشان می دهد که در آینده هیچ رویداد دیگری منتشر نخواهد شد.readable
: زمانی که داده ها در جریان قابل خواندن برای خواندن در دسترس هستند، منتشر می شود.
رویدادها در جریانهای قابل نوشتن
close
: هنگامی که منبع جریان بسته است منتشر می شود و نشان می دهد که در آینده هیچ رویداد دیگری منتشر نخواهد شد.error
: هنگامی که خطایی در هنگام خواندن رخ می دهد منتشر می شود. این ممکن است در صورتی اتفاق بیفتد که جریان قابل نوشتن به دلیل برخی از خرابی های داخلی نتواند داده تولید کند یا زمانی که داده های تکه نامعتبر به جریان فشار داده می شود.finish
: زمانی منتشر می شود که تمام داده ها از جریان قابل نوشتن پاک شوند.pipe
: هنگامی که جریان قابل نوشتن به یک جریان قابل خواندن لوله می شود، منتشر می شود.unpipe
: هنگامی که جریان قابل نوشتن از یک جریان قابل خواندن خارج می شود، منتشر می شود.
نتیجه
به عبارت ساده تر، جریان ها برای خواندن از ورودی یا نوشتن به صورت متوالی در خروجی استفاده می شوند. بیشتر اوقات، جریان ها برای خواندن یا نوشتن از یک منبع پیوسته یا یک منبع نسبتاً بزرگ استفاده می شوند.
ماژول Stream یک ماژول بومی است که به طور پیش فرض در Node.js ارسال می شود. را Stream
نمونه ای از EventEmitter
کلاس، که رویدادها را به صورت ناهمزمان در Node.js مدیریت می کند. به دلیل سوپرکلاسی که دارند، جریان ها ذاتاً مبتنی بر رویداد هستند.
جریان های دگرگونی در این مقاله پوشش داده نشدند، زیرا آنها مقاله خود را تضمین می کنند.
کد منبع این پروژه موجود است روی GitHub مثل همیشه. اگر در طول آموزش گیر کردید از این برای مقایسه کد خود استفاده کنید.
اگر اطلاعات بیشتری در مورد جریانها و یا دانش پیشرفته میخواهید، توصیه میشود دنبال کنید اسناد رسمی برای استریم ها
(برچسبها برای ترجمه)# جاوا اسکریپت
منتشر شده در 1403-01-24 06:28:04