راهنمای پذیرش RxJS: بررسی اجمالی، مثالها و جایگزینها

Summarize this content to 400 words in Persian Lang
نوشته امانوئل اودیوکو✏️
کتابخانه Reactive Extensions برای جاوا اسکریپت یا RxJS به دلیل اینکه یک کتابخانه برنامه نویسی واکنشی است که از Observables استفاده می کند مشهور است. اگر این برای شما منطقی نیست، نگران نباشید – به همین دلیل است که این راهنما مرتبط است.
در این راهنمای پذیرش، با ویژگیها، مزایا و موارد دیگر RxJS آشنا میشویم تا به شما کمک کنیم بفهمید چیست، چگونه کار میکند و چرا باید از آن استفاده کنید. در پایان این راهنما، میتوانید تشخیص دهید که چه زمانی و چگونه آن را به طور مؤثر در پروژههای خود بپذیرید.
مقدمه ای بر RxJS
در حدود سال 2011، تیم برنامهنویسی ابری مایکروسافت نیاز داشت تا رویدادها را در بخشهای مختلف یک برنامه بهتر مدیریت کند. این نیاز باعث ایجاد پروژه ای به نام Volta شد، یک مجموعه ابزار آزمایشی با هدف ساده سازی توسعه برنامه های کاربردی وب چند لایه.
RxJS بخشی از این پروژه بود. لوگوی آن، که دارای یک مارماهی الکتریکی است، اشاره ای به ولتا است. در همین حال، «افزونهها» به فناوری دیگری به نام افزونههای موازی توسعهیافته در همان زمان اشاره دارد که به خوبی کتابخانه پسوندهای واکنشی (Rx) را تکمیل میکند.
اولین نسخه Rx برای چارچوب دات نت ساخته شد و در 21 ژوئن 2011 منتشر شد. بعداً، تیم پیاده سازی Rx را برای جاوا اسکریپت، RxJS، همراه با نسخه هایی برای زبان های دیگر مانند C++ ایجاد کرد. در اواخر سال 2012، RxJS به عنوان نرم افزار منبع باز، ابتدا در CodePlex منتشر شد و بعداً به GitHub منتقل شد.
شروع کار با RxJS
راستش برنامه نویسی واکنشی به خصوص در ابتدا آسان نیست. با این حال، هر چه بیشتر با آن کار کنید دشوارتر می شود، بنابراین شروع هر چه زودتر می تواند مفید باشد.
برای شروع، به درک نکات زیر نیاز دارید:
اصول جاوا اسکریپت – این شامل درک نحوه اعلان و فراخوانی توابع، و همچنین آگاهی از نحوه مدیریت رویدادها در جاوا اسکریپت با استفاده از شنوندگان رویداد است. آشنایی با try…catch بلوک ها نیز کارایی شما را افزایش می دهند
جاوا اسکریپت ناهمزمان – شما باید اصول اولیه تماسهای برگشتی را بدانید و Promise API از جمله نحوه ایجاد و مصرف وعدهها را بدانید. درک خوب در مورد نحوه استفاده از async و انتظار برای مدیریت عملیات ناهمزمان نیز بسیار قدردانی خواهد شد.
RxJS نصب شده است – مراحل زیر را برای راهنمایی شما بررسی کنید
برای نصب RxJS، یک دایرکتوری جدید ایجاد کنید. به خاطر این آموزش، می توانید آن را نام ببرید RxJs-Guide. به داخل آن بروید، ترمینال را باز کنید و با اجرای این دستور یک پروژه Node جدید را مقداردهی اولیه کنید:
npm init -y
وارد حالت تمام صفحه شوید
از حالت تمام صفحه خارج شوید
در مرحله بعد باید RxJS را نصب کنیم. برای انجام این کار، باید این دستور را اجرا کنید:
npm install rxjs
وارد حالت تمام صفحه شوید
از حالت تمام صفحه خارج شوید
بیشتر خواندن:
RxJS چیست؟
در برنامه های نرم افزاری، وابستگی زیادی به عملیات ناهمزمان وجود دارد که شامل واکشی داده ها از API ها می شود. RxJS شیوه برخورد ما با این داده ها را متحول کرده است – به ما این امکان را می دهد تا با ارائه ابزارهایی برای دستکاری داده های ناهمزمان، با داده ها مانند جریان ها رفتار کنیم. این ابزارها عبارتند از Observables، Observers، Operators، Subscriptions، Subjects و Schedulers.
بعداً با جزئیات بیشتری به نحوه عملکرد RxJS خواهیم پرداخت، اما در حال حاضر به عنوان یک تشبیه سریع، میتوانید آن را به عنوان یک سرویس پخش زنده ورزشی محلی شخصی در نظر بگیرید.
در این سرویس، Observables یا جریان های داده، کانال های پخش هستند، در حالی که ناظران، بینندگانی هستند که برای دریافت رویدادهای زنده در این کانال ها مشترک می شوند. هنگامی که بیننده مشترک می شود، بلافاصله شروع به دریافت پخش می کند و می تواند در هر زمان اشتراک خود را لغو کند تا آن را متوقف کند.
اپراتورها به عنوان فیلترهایی برای سفارشی کردن پخش عمل می کنند، مانند پرش از تبلیغات یا برجسته کردن لحظات کلیدی. زمانبندها زمان و ترتیب پخشها را مدیریت میکنند، در حالی که Subjects Observableهای ویژهای هستند که پخش یکسانی را با همه بینندگان بهطور همزمان به اشتراک میگذارند و اطمینان حاصل میکنند که همه یک رویداد را در یک زمان میبینند.
ویژگی های کلیدی RxJS که باید بدانید
در بخش قبل، توضیح سادهای درباره نحوه عملکرد RxJS برای ارائه درک سطح بالا بدون گم شدن در جزئیات فنی بررسی کردیم. در ادامه، برخی از اصطلاحات فنی را تعریف میکنیم و به نمونههایی از موارد استفاده از این ویژگیها میپردازیم.
ما این بخش را به دو قسمت تقسیم می کنیم. ابتدا در مورد Observables، Observers و Subscriptions بحث خواهیم کرد و دانش خود را با ساختن یک سیستم RxJS ساده عملی می کنیم. سپس، در مورد اپراتورها، موضوعها و زمانبندها بحث خواهیم کرد و سیستم RxJS خود را با این ویژگیها گسترش میدهیم تا یک مورد استفاده واقعی را نشان دهیم.
قابل مشاهده
احتمالاً در هر تعریف RxJS Observables را پیدا خواهید کرد. اما Observables دقیقا چیست؟
قابل مشاهده ها مانند توابعی هستند که هیچ ورودی دریافت نمی کنند اما می توانند در طول زمان بیش از یک مقدار تولید کنند و آنها را به سمت ناظران سوق دهند. مانند توابع، Observable ها تنبل هستند و باید مشترک شوند.
شباهت هایی بین Observables و the وجود دارد EventEmitter کلاسی که می تواند باعث شود ما آنها را گیج کنیم، اما عملکرد آنها کمی متفاوت است. یک تفاوت قابل توجه این است که یک EventEmitter مشتاق است در حالی که Observables تنبل هستند و تا زمانی که در آنها مشترک نشوید شروع به تولید داده نمی کنند.
در اینجا جدولی برای کمک به درک تفاوت بین Observables، توابع و an وجود دارد EventEmitter در یک نگاه:
تایپ کنید
استراتژی بارگیری
مکانیسم داده
خروجی
قابل مشاهده
تنبل
فشار دادن
مقادیر چندگانه
کارکرد
تنبل
کشیدن
ارزش واحد
Event Emitter
مشتاق
فشار دادن
مقادیر چندگانه
بیشتر خواندن:
مشاهده کننده
ما در قیاس قبلی خود از Observables به عنوان کانال های پخش به جریان های داده اشاره کردیم. یک جریان یک روش عالی برای توصیف نوع بسته بندی داده های مشاهده پذیر است، زیرا یک مشاهده پذیر مانند کانالی است که داده ها در طول زمان از طریق آن جریان می یابد.
میتوانید این کانال را تماشا کنید و دادههای جدیدی را که وارد میشوند، به صورت همزمان یا ناهمزمان دریافت کنید. به عنوان مثال، این دادهها میتواند جریانی از اعداد، کلیکها یا پیامها باشد که میتوانید هر زمان که قطعه جدیدی وارد میشود به آنها واکنش نشان دهید.
ناظران در عین حال توانایی واکنش به این جریان داده را فراهم می کنند. هر زمان که مقدار یا پیام خطای جدیدی دریافت کنیم، کدی را اجرا می کنند. Observer سه روش را پیاده سازی می کند:
next() هر زمان که مقدار جدیدی منتشر شود توسط Observable فراخوانی می شود
error() هر زمان که Observable خطا می دهد فراخوانی می شود
complete() هر زمان که Observable انجام شود فراخوانی می شود
توجه داشته باشید که یک Observable ممکن است هرگز تمام نشود، که به دلیل فعالیت کاربر است.
برای مثال، اگر یک Observable در اطراف a پیچیده شده باشد clickListener در یک دکمه، هر بار که کاربر روی دکمه کلیک می کند، با انتشار یک مقدار یا پرتاب یک خطا واکنش نشان می دهد. شما نمی دانید چه زمانی تمام می شود، زیرا بستگی به زمانی دارد که کاربر کلیک را متوقف کند.
اینجاست که اشتراک ها وارد می شوند. در ادامه ببینیم یک اشتراک در RxJS چگونه کار می کند.
اشتراک، ابونمان
یک اشتراک به Observable اجازه می دهد بداند چه زمانی باید یک متد Observer را فراخوانی کند. با استفاده از subscribe روش، میتوانیم به Observable بگوییم که Observer به مقادیری که منتشر میکند اهمیت میدهد. شما هم می توانید subscribe یا unsubscribe به جریان داده ها
مجموعه نمودارهای زیر به شما کمک می کند تا Observables، Observers و Subscriptions را درک کنید. ابتدا، بیایید ببینیم چگونه یک Observable در اطراف جریانی از مقادیر قرار می گیرد: این نقش Observers را معرفی می کند که برای مدیریت یک مقدار یا بیش از یک مقدار معرفی می شوند: اشتراک زمانی اتفاق می افتد که Observer شروع به گوش دادن به Observable کند. در این مرحله، Observable شروع به ارسال مقادیر به Observer می کند و باعث می شود next()، error()، و complete() روشهایی که Observable مقادیر را منتشر میکند، با خطا مواجه میشود یا تکمیل میکند، به ترتیب: همانطور که قبلاً اشاره کردیم، همه مشاهده پذیرها به پایان نمی رسند، اما برخی پایان می یابند.
به عنوان مثال، یک قابل مشاهده که داده ها را از یک API واکشی می کند، پایان می یابد. یک درخواست HTTP GET برای دریافت دادههای کاربر ایجاد میکند، پس از واکشی دادهها را منتشر میکند، و سپس تکمیل میشود و هرگونه انتشار بیشتر را متوقف میکند. در چنین مواردی، complete متد به طور خودکار پس از واکشی و ارسال داده ها فراخوانی می شود: همچنین میتوانیم جریانی داشته باشیم که در نقطهای از زمان خطا ایجاد کند. به عنوان مثال، زمانی که ما یک درخواست HTTP می کنیم، پاسخی که دریافت می کنیم می تواند یک خطای سمت سرور باشد. در مواردی مانند این، Observable خطا را پرتاب میکند، که ما میتوانیم آن را مدیریت کنیم error تابع: اکنون که دیدیم Observables، Observers و Subscriptions چیست، اجازه دهید آنها را به کار بیندازیم. ما در حال ساختن یک سیستم RxJS هستیم که در آن یک Observable داریم که برخی از داده ها را منتشر می کند.
ساختن یک سیستم RxJS با Observables، Observers و Subscriptions
اگر مراحل راهاندازی را در بخش شروع با RxJS ما دنبال کردهاید، باید یک پروژه اولیه را از قبل تنظیم کرده باشید. به دایرکتوری پروژه خود بروید، آن را در هر ویرایشگر کد مورد نظر خود باز کنید – من از VS Code استفاده می کنم – و یک index.js فایل.
در این فایل ابتدا یک Observable ایجاد می کنیم، سپس یک Observer ایجاد می کنیم و در نهایت آنها را با یک Subscription متصل می کنیم و کد را اجرا می کنیم. با وارد کردن یک RxJS Observable مانند زیر شروع کنید:
const {Observable} = require(‘rxjs’);
وارد حالت تمام صفحه شوید
از حالت تمام صفحه خارج شوید
بعد، بیایید نمونه سازی کنیم Observable کلاس و یک تابع برای ایجاد Observable ما به آن ارسال کنید. این تابع یک را می گیرد subscriber شی به عنوان آرگومان، که برای انتشار مقادیر، رسیدگی به خطاها و تکمیل سیگنال استفاده می شود. به یاد داشته باشید که یک Observable می تواند چندین مقدار را منتشر کند و ما بیش از یک مقدار را منتشر خواهیم کرد. کد به شکل زیر است:
//Create an observable
const observable = new Observable((subscriber) => {
subscriber.next(100);
subscriber.next(200);
subscriber.next(300);
subscriber.complete();
});
وارد حالت تمام صفحه شوید
از حالت تمام صفحه خارج شوید
اگر به خاطر داشته باشید، Observer یک شی است که اختیاری دارد next()، error()، و complete() مواد و روش ها. ما از این روش ها استفاده خواهیم کرد:
next() مقدار دریافتی را در کنسول ثبت می کند
error() خطای دریافتی را در کنسول ثبت می کند
complete() گزارش هایی که قابل مشاهده کامل شده است
بیایید اکنون Observer خود را ایجاد کنیم:
//create an Observer
const observer = {
next: (value) => console.log(“The observer received a value” + value),
error: (error) => console.log(“The observer received an error” + error),
complete: () => console.log(‘observer is complete’)
}
وارد حالت تمام صفحه شوید
از حالت تمام صفحه خارج شوید
در نهایت، ما باید Observable را با یک اشتراک به Observer متصل کنیم:
//connect the observable and the observer
observable.subscribe(observer);
وارد حالت تمام صفحه شوید
از حالت تمام صفحه خارج شوید
این خط واحد را صدا می کند subscribe متد روی Observable است و Observer را به عنوان آرگومان ارسال می کند. هنگامی که Observable مشترک شد، شروع به انتشار مقادیر می کند. وقتی ما اجرا می کنیم node index.js دستور، مقادیر ثبت شده در زیر را خواهیم داشت: اکنون که مفهوم اصلی را نشان دادیم، بیایید یک سناریوی واقعیتر را امتحان کنیم که شامل کاری است که ممکن است هر از چند گاهی به عنوان توسعهدهنده انجام دهیم. ما می خواهیم که Observer ما داده های کاربر را منتشر کند تا بتوانیم دسترسی به برنامه خود را برای کاربران فعال 18 ساله و بالاتر محدود کنیم:
data: [
{
status: “inactive”,
name: “John”,
age: 17
},
{
status: “active”,
name: “Jane”,
age: 25
},
{
status: “inactive”,
name: “Joe”,
age: 16
},
{
status: “active”,
name: “Jill”,
age: 35
},
{
status: “active”,
name: “Jack”,
age: 45
},
{
status: “inactive”,
name: “Jill”,
age: 35
},
{
status: “active”,
name: “Jill”,
age: 12
}
]
وارد حالت تمام صفحه شوید
از حالت تمام صفحه خارج شوید
این ما را به اپراتورها، زمانبندیها و موضوعات در RxJS میبرد. بیایید این اصطلاحات را تعریف کنیم و درک درستی از نحوه اعمال آنها در پروژه آزمایشی خود داشته باشیم.
اپراتورها
اپراتورها برای نوشتن کدهای ناهمزمان پیچیده به شیوه ای واضح و شفاف بسیار مهم هستند. ما می توانیم از عملگرها برای دستکاری Observables استفاده کنیم. آنها به دو صورت می آیند:
اپراتورهای Pipeable: این عملگرها توابعی هستند که می توان با استفاده از آن به یکدیگر زنجیره زد .pipe() روش روی یک مشاهده پذیر مثالها عبارتند از map، filter، و mergeMap. اپراتورهای Pipeable یک Observable را به عنوان ورودی می گیرند و یک Observable جدید را برمی گردانند که امکان تبدیل جریان داده انعطاف پذیرتر را فراهم می کند.
اپراتورهای ایجاد: این عملگرها Observableهای جدید را از منابع مختلف مانند رویدادها، تایمرها یا دیگر ساختارهای داده ایجاد می کنند. مثالها عبارتند از of، from، و interval. ما می توانیم از این عملگرها برای تولید Observables از ابتدا استفاده کنیم و زمینه را برای پردازش جریان داده ها فراهم کنیم
همانطور که در بالا ذکر شد، ما می خواهیم پروژه آزمایشی خود را به روز کنیم تا کاربران غیرفعال و زیر 18 سال را فیلتر کنیم. ابتدا باید داده های کاربر را منتشر کنیم، بنابراین منبع داده را همانطور که در زیر مشاهده می کنید دریافت می کنیم:
const users = {
data: [
{
status: “inactive”,
name: “John”,
age: 17
}, //fill in the remaining data…
]
}
وارد حالت تمام صفحه شوید
از حالت تمام صفحه خارج شوید
در مرحله بعد، داده های کاربر را برای مشترکین ارسال می کنیم:
const observable = new Observable((subscriber) => {
subscriber.next(users.data);
subscriber.complete();
})
وارد حالت تمام صفحه شوید
از حالت تمام صفحه خارج شوید
برای فیلتر کردن کاربران بر اساس فعالیت و سن آنها، باید آن را وارد کنیم map و filter عملگرها از RxJS و اعمال آنها بر روی Observable با استفاده از .pipe() روش. استفاده خواهیم کرد map برای تبدیل داده های منتشر شده توسط مشاهده پذیر، و filter اپراتور برای حذف مشروط کاربرانی که معیارهای مشخص شده را ندارند:
const observable = new Observable((subscriber) => {
subscriber.next(users.data);
subscriber.complete();
}).pipemap(users => users.filter(user => (user.status === ‘inactive’ && user.age 18)))
وارد حالت تمام صفحه شوید
از حالت تمام صفحه خارج شوید
برای مشاهده نتیجه، Observer بعدی را با این جایگزین کنید:
next: (value) => console.log(“The observer received active users” + JSON.stringify(value,null, 2))
وارد حالت تمام صفحه شوید
از حالت تمام صفحه خارج شوید
و کد را اجرا کنید:
بیشتر خواندن:
فاعل، موضوع
سوژه ها انواع خاصی از Observables هستند که می توانند چندپخشی باشند، به این معنی که بیش از یک ناظر می توانند مشترک یک موضوع واحد شوند. در مقابل، مشاهدهپذیرهای معمولی فقط میتوانند یکپارچه باشند و یک رابطه یک به یک بین مشاهدهپذیر و مشاهدهکنندگان آن داشته باشند.
هر موضوعی هم ناظر و هم قابل مشاهده است. این ماهیت دوگانه به سوژهها اجازه میدهد نه تنها دادهها را دریافت کنند (مانند مشاهدهگر) بلکه دادهها را نیز منتشر کنند (مانند یک مشاهدهپذیر).
سوژه ها می توانند چندپخشی باشند، که می تواند در سناریوی دنیای واقعی ما مهم باشد. فرض کنید چندین بخش از برنامه خود دارید که باید به لیست فیلتر شده کاربران واکنش نشان دهند. یک موضوع به شما امکان می دهد نتایج فیلتر شده را برای همه مشترکین چندپخش کنید.
برای استفاده از یک موضوع در RxJS، باید این ماژول ها را وارد کنید:
const { Subject } = require(‘rxjs’);
const { map } = require(‘rxjs/operators’);
وارد حالت تمام صفحه شوید
از حالت تمام صفحه خارج شوید
این نقشه راه یا جریان اجرایی است که برای اجرای Subjects استفاده خواهیم کرد:
ايجاد كردن userSubject
تعريف كردن observer1 و observer2
مشترک شدن هر دو ناظر در userSubject با لوله ای که کاربران را فیلتر می کند
userSubject.next(users.data) داده های کاربر را منتشر می کند
هر دو مشاهده کننده لیست فیلتر شده کاربران غیرفعال زیر 18 سال را دریافت می کنند
userSubject.complete() فراخوانی می شود و به هر دو ناظر اطلاع داده می شود که جریان کامل شده است
در اینجا نحو برای ایجاد یک است userSubject:
const userSubject = new Subject();
وارد حالت تمام صفحه شوید
از حالت تمام صفحه خارج شوید
در این مورد، userSubject نمونه جدیدی از a است Subject. ما از آن برای ارسال دادههای کاربر به دو مشاهدهگر خود استفاده میکنیم که میتوانیم آنها را به این صورت ایجاد کنیم:
const observer1 = {
next: (value) => console.log(“Observer 1 received: ” + JSON.stringify(value, null, 2)),
error: (error) => console.log(“Observer 1 received an error: ” + error),
complete: () => console.log(‘Observer 1 is complete’)
};
const observer2 = {
next: (value) => console.log(“Observer 2 received: ” + JSON.stringify(value, null, 2)),
error: (error) => console.log(“Observer 2 received an error: ” + error),
complete: () => console.log(‘Observer 2 is complete’)
};
وارد حالت تمام صفحه شوید
از حالت تمام صفحه خارج شوید
سپس باید ناظران خود را در موضوع مشترک کنیم:
userSubject.pipe(
map(users => users.filter(user => user.status === ‘inactive’ && user.age 18))
).subscribe(observer1);
userSubject.pipe(
map(users => users.filter(user => user.status === ‘inactive’ && user.age 18))
).subscribe(observer2);
وارد حالت تمام صفحه شوید
از حالت تمام صفحه خارج شوید
در نهایت، ما داده ها را منتشر می کنیم و موضوع را تکمیل می کنیم:
userSubject.next(users.data);
userSubject.complete();
وارد حالت تمام صفحه شوید
از حالت تمام صفحه خارج شوید
با استفاده از یک موضوع، میتوانیم اطمینان حاصل کنیم که همه مؤلفهها یا جریانهایی که نیاز به نمایش دادههای فیلتر شده دارند، هر زمان که منبع داده اصلی تغییر کند، همان دادههای بهروزرسانی شده را دریافت میکنند.
بیشتر خواندن:
برنامه ریزان
تا اینجا ما Observables، Observers، Subscriptions، Operators و Subjects را دیده ایم. آخرین ویژگی که در مورد آن بحث خواهیم کرد، Schedulers است.
ما یاد گرفتیم که Subscriptions Observables و Observer را به هم متصل می کند، اما Schedulers اجرای این اشتراک ها را مدیریت می کند. یک Scheduler زمان شروع اجرای Observables و زمان تحویل مقادیر به Observer را کنترل می کند.
بیایید با استفاده از یک مثال ساده کمی Schedulers را تجزیه کنیم. در جاوا اسکریپت، وظایف به میکرووظیفه ها و ماکروتسک ها طبقه بندی می شوند که بر ترتیب اجرای آنها در حلقه رویداد تأثیر می گذارد. تصور کنید چندین کار با اولویت بالا (وظیفه های کوچک) و معمولی (macrotasks) برای تکمیل در یک روز دارید:
Regular log: یک تماس تلفنی سریع که بلافاصله شروع می کنید
process.nextTick: پیامک فوری که به محض قطع کردن تلفن به آن پاسخ می دهید
Promise.resolve: ایمیلی با اولویت بالا که بلافاصله بعد از متن فوری ارسال می کنید
setTimeout: یک استراحت ناهار برای بعد از کارهای فوری برنامه ریزی شده است
setImmediate: یک استراحت چای بعد از ظهر که بعد از انجام تمام کارهای برنامه ریزی شده دیگر اتفاق می افتد
وظایفی مانند process.nextTick و Promise.resolve() وظایف خرد هستند و بلافاصله انجام می شوند. در همین حال، وظایف ماکرو مانند setTimeout و setImmediate برای مدتی بعد برنامه ریزی می شوند و اطمینان حاصل می شود که کارهای منظم پس از کارهای با اولویت بالا تکمیل می شوند:
// Regular console log
console.log(‘Regular log’);
// setTimeout
setTimeout(() => console.log(‘setTimeout’), 0);
// Promise.resolve
Promise.resolve().then(() => console.log(‘Promise.resolve’));
// setImmediate
setImmediate(() => console.log(‘setImmediate’));
// process.nextTick
process.nextTick(() => console.log(‘process.nextTick’));
وارد حالت تمام صفحه شوید
از حالت تمام صفحه خارج شوید
اگر کد بالا را اجرا کنید، نتیجه به شکل زیر خواهد بود:
Regular log
process.nextTick
Promise.resolve
setTimeout
setImmediate
وارد حالت تمام صفحه شوید
از حالت تمام صفحه خارج شوید
اکنون، جریانها در RxJS میتوانند همزمان و ناهمزمان باشند. بنابراین اگر بخواهیم کنترل کنیم که جریان های ما در چه زمینه ای اجرا می شوند چه؟ زمانبندیهای کلیدی برای این کار وجود دارد که عبارتند از:
asyncScheduler – Observables را به صورت ناهمزمان اجرا می کند
queueScheduler – Observables را به صورت همزمان در یک صف اجرا می کند
animationFrameScheduler – وظایف را قبل از فریم انیمیشن مرورگر بعدی برنامه ریزی می کند
برای ادغام یک Scheduler، از observeOn و subscribeOn اپراتورها به ترتیب Scheduler را برای مشاهده و اشتراک مشخص کنند. در اینجا نحوه ادغام یک Scheduler به صورت همزمان آورده شده است:
const { of, queueScheduler } = require(‘rxjs’);
const { observeOn } = require(‘rxjs/operators’);
// Synchronous task with queueScheduler
of(‘Synchronous task’).pipe(
observeOn(queueScheduler)
).subscribe(value => console.log(value));
وارد حالت تمام صفحه شوید
از حالت تمام صفحه خارج شوید
و در اینجا نحوه ادغام یک Scheduler به صورت همزمان آورده شده است:
const { of, asyncScheduler } = require(‘rxjs’);
const { observeOn } = require(‘rxjs/operators’);
// Asynchronous task with asyncScheduler
of(‘Asynchronous task’).pipe(
observeOn(asyncScheduler)
).subscribe(value => console.log(value));
وارد حالت تمام صفحه شوید
از حالت تمام صفحه خارج شوید
مزایا و معایب RxJS
قبلاً ویژگیهای RxJS را برجسته کردهام، اما میخواهم چند دلیل را توضیح دهم که چرا فکر میکنم این یک انتخاب عالی است. برای کمک به ارزیابی منصفانه آن، من همچنین در مورد برخی از ملاحظات که باید در نظر داشته باشید صحبت خواهم کرد.
کارایی
به طور کلی، RxJS بسیار سریع است، اما عملکرد آن می تواند بر اساس نحوه نوشتن و مدیریت کد، به ویژه در مورد اشتراک ها و ساختارهای پیچیده قابل مشاهده متفاوت باشد. اپراتورها برای کارایی بالا طراحی شده اند، اما با این وجود، خوب است به خاطر داشته باشید که اجرای کد کمتر همیشه سریعتر از کد بیشتر خواهد بود.
سهولت استفاده، DX و منحنی یادگیری
ممکن است کمی طول بکشد تا سر خود را به دور RxJS بپیچید و تجربه بودن شما را از منحنی یادگیری شیب دار آن معاف نمی کند.
برای استفاده مؤثر از RxJS در پروژههای دنیای واقعی، باید از نمونههای اولیه نشان داده شده در این وبلاگ فراتر بروید. بسیاری از توسعه دهندگان به این حد نمی رسند، که قابل درک است، زیرا نامگذاری اپراتورها و خود اپراتورهای پیشرفته می تواند بسیار خسته کننده باشد.
با این حال، هنگامی که اصول RxJS را درک کنید و شروع به استفاده از آن کنید، همه چیز بسیار ساده تر می شود. شما شروع به قدردانی خواهید کرد که RxJS چگونه کارآمد است. اگر بتوانید منحنی یادگیری را پشت سر بگذارید، RxJS میتواند ابزار قدرتمندی برای اهرمسازی باشد.
اندازه بسته
RxJS v7 نسبت به نسخه قبلی خود کاهش قابل توجهی در اندازه دارد. اگر برنامه شما از تمام اپراتورهای RxJS v6 استفاده می کرد، به 52 کیلوبایت نیاز داشت. با این حال، با نسخه 7، این مقدار به 19 کیلوبایت کاهش می یابد.
چه این شما را تحت تأثیر قرار دهد یا نه، مهم است به خاطر داشته باشید که در مناطقی با اتصالات اینترنتی بسیار بد، هر کیلوبایت ذخیره شده می تواند به طور قابل توجهی بر عملکرد و UX تأثیر بگذارد.
جامعه و اکوسیستم ها
RxJS دارای یک جامعه قوی با بیش از 11.2 میلیون کاربر، 500 مشارکت کننده و 30 هزار ستاره در Github است. این اعداد یک جامعه فعال با پشتیبانی از React، Angular، Vue و SolidJS در اکوسیستم جاوا اسکریپت را نشان میدهند.
با این سطح از پشتیبانی جامعه، بعید است که با مشکلاتی روبرو شوید که قبلاً به صورت آنلاین حل نشده است. در نتیجه، با وجود منحنی یادگیری تا حدودی شیب دار، شما منابع زیادی در سفر خود با استفاده از RxJS دارید.
مستندات
اسناد RxJS راه زیادی را در جزئیات هر چیزی که برای پیادهسازی اپراتورهای خود لازم است انجام میدهند، که بسیار مهم است زیرا بیش از 100 اپراتور دارد که هر کدام برای انجام وظایف خاصی روی Observables طراحی شدهاند.
با وجود داشتن بیش از 100 اپراتور برای استفاده، بر اساس تجربه شخصی، به احتمال زیاد فقط باید حدود 50 یا کمتر را بدانید و از 25 مورد از آن ها در پروژه های خود استفاده کنید. البته، این موضوع به موارد استفاده خاص شما بستگی دارد، اما به داشتن اسناد دقیقی کمک می کند که به وضوح توضیح دهند که کدام یک، چرا، و چگونه باید استفاده شود.
ادغام با سایر کتابخانه ها و چارچوب ها
ادغام RxJS با کتابخانه ها و چارچوب های مختلف جاوا اسکریپت نسبتاً ساده است. در Angular، RxJS داخلی است و معمولاً برای مدیریت عملیات ناهمزمان استفاده می شود. RxJS همچنین با React، Node.js، Vue، Svelte و SolidJS ادغام می شود.
اگرچه RxJS ممکن است همیشه گزینه مناسب یا جایگزین کاملی برای کتابخانههای خاص نباشد – مانند React Query، راهی برای مدیریت واکشی ناهمزمان داده در React – هنوز برای بسیاری از سناریوهای دیگر مناسب است. اما در سراسر اکوسیستم جاوا اسکریپت، RxJS قابلیت های قدرتمندی را برای مدیریت وظایف پیچیده ناهمزمان و برنامه نویسی واکنشی فراهم می کند.
اشکال زدایی
اشکال زدایی در RxJS شامل استفاده از ابزارهایی مانند عملگر tap برای ثبت مقادیر قابل مشاهده و ایجاد عملگرهای اشکال زدایی سفارشی برای سطوح ثبت انعطاف پذیر است. این رویکرد به شناسایی زودهنگام مشکلاتی مانند نشت حافظه و اشتراکهای متعدد کمک میکند و قابلیت نگهداری کد و نظارت بر عملکرد را افزایش میدهد.
در حالی که اشکال زدایی می تواند کمی استرس زا باشد، این مشکل فقط برای RxJS نیست. RxJS در طول سالها تکامل یافته است، و اگرچه ممکن است این تجربه در همه فریمورکها روان نباشد، مزایای آن ممکن است ارزش سرمایهگذاری برای یادگیری را داشته باشد.
از موارد برای RxJS استفاده کنید
RxJS بسیار متنوع است. در اینجا فقط چند نمونه از موارد استفاده آورده شده است، با آموزش های مرتبط اگر می خواهید جزئیات بیشتری را بررسی کنید:
مدیریت حالت در React: میتوانید RxJS را با React Hooks برای مدیریت حالت ادغام کنید و یک رویکرد عملکردی و واکنشی برای مدیریت تغییرات حالت و جریانهای داده ناهمزمان ارائه دهید.
تبدیل داده ها در TypeScript: RxJS برای تبدیل جریان های داده در TypeScript بسیار موثر است و به توسعه دهندگان این امکان را می دهد تا تغییرات و دستکاری های پیچیده را روی داده های قابل مشاهده اعمال کنند.
ساختن یک برنامه جستجوی ویدیوی YouTube: میتوانید از RxJS برای ساخت یک برنامه استریم استفاده کنید، که قدرت آن را در مدیریت درخواستهای HTTP ناهمزمان و بهروزرسانی واکنشی رابط کاربری نشان میدهد.
فراتر از این، RxJS یک گزینه عالی برای هر گونه برنامه نویسی واکنشی و نیازهای مدیریت دولتی است.
RxJS در مقابل Bacon.js در مقابل سیگنال
در این بخش، جایگزین های فرضی RXJS را با هم مقایسه می کنیم و نقاط قوت آنها را نیز برجسته می کنیم.
شاخص
RxJS
Bacon.js
سیگنال ها
امکانات
برنامه نویسی واکنشی با مشاهده پذیرها، مجموعه ای غنی از عملگرها، از رویدادهای ناهمزمان و جریان های داده پشتیبانی می کند.
بسیار شبیه به RxJS با این تفاوت که دو نوع Observable وجود دارد – EventStream و Property
مدیریت حالت واکنشی برای Angular. بر واکنش پذیری و تشخیص تغییر تمرکز می کند. به طور یکپارچه با اکوسیستم Angular ادغام می شود
کارایی
در صورت استفاده صحیح عملکرد بالایی را ارائه می دهد. به مدیریت اشتراک ها و Observable ها بستگی دارد
سابقه عملکرد خوبی دارد
بهینه شده برای برنامه های Angular، عملکرد را با کاهش چرخه های تشخیص تغییر بهبود می بخشد، و در مدیریت حالت واکنش بسیار کارآمد است.
انجمن
جامعه بزرگ و فعال با پشتیبانی گسترده از اکوسیستم های مختلف جاوا اسکریپت.
جامعه در حال رشد، با بیش از 86 مشارکتکننده و 6.5 هزار ستاره
انجمن Angular به طور فعال سیگنال ها را حفظ کرده و قویاً پشتیبانی می کند
اسناد/منابع
[Comprehensive documentation](https://rxjs.dev/guide/overview)، آموزش ها و نمونه های زیادی در همه جا به صورت آنلاین موجود است. یکی از کتابخانه های واکنشی که بیشترین پشتیبانی را داردخیلی [bogus documentation](https://github.com/baconjs/bacon.js)، اما موارد استفاده API با جزئیات خوبی دارد
بسیار مفصل [documentation](https://github.com/angular/angular/discussions/49685) و مثال
چارچوب ها
React، Angular و فریمورک های دیگر
فریمورک های سازگار با TypeScript مانند Angular، React (با TypeScript) و Vue.js (با TypeScript)
مخصوص Angular
با توجه به مقایسه ما، RxJS در مدیریت عملیات ناهمزمان پیچیده و جریان های داده برتری دارد. در همین حال، Bacon.js همچنین بر مدیریت عملیات ناهمزمان پیچیده، به ویژه در اکوسیستم React تمرکز دارد. در نهایت، سیگنال یک رویکرد کاربردی برای مدیریت برنامههای ناهمزمان و واکنشپذیر مخصوص Angular ارائه میکند.
بیشتر خواندن:
نتیجه
پذیرش RxJS امروز به طور قابل توجهی توانایی شما را برای مدیریت عملیات ناهمزمان و ساخت برنامه های واکنشی بهبود می بخشد. با دانش درست در این مقاله، دلیل کافی برای استفاده از RxJS دارید. امروز RxJS را امتحان کنید!
آیا کتابخانه های جدید JS را برای ایجاد ویژگی های جدید یا بهبود عملکرد اضافه می کنید؟ اگر برعکس عمل کنند چه؟
شکی نیست که فرانت اندها پیچیده تر می شوند. همانطور که کتابخانه های جدید جاوا اسکریپت و وابستگی های دیگر را به برنامه خود اضافه می کنید، برای اطمینان از اینکه کاربران شما با مشکلات ناشناخته مواجه نمی شوند، به دید بیشتری نیاز دارید.
LogRocket یک راه حل مانیتورینگ برنامه کاربردی است که به شما امکان می دهد خطاهای جاوا اسکریپت را به گونه ای تکرار کنید که گویی در مرورگر شما اتفاق افتاده است تا بتوانید به طور موثرتری به باگ ها واکنش نشان دهید.
LogRocket بدون در نظر گرفتن چارچوب، با هر برنامه ای کاملاً کار می کند و دارای پلاگین هایی برای ثبت زمینه اضافی از Redux، Vuex، و @ngrx/store است. به جای حدس زدن چرایی مشکلات، می توانید در مورد وضعیتی که برنامه شما در هنگام بروز مشکل در آن قرار داشت، جمع آوری کرده و گزارش دهید. LogRocket همچنین عملکرد برنامه شما را نظارت می کند، معیارهایی مانند بار CPU مشتری، استفاده از حافظه مشتری و موارد دیگر را گزارش می دهد.
با اطمینان بسازید – نظارت را به صورت رایگان شروع کنید.
نوشته امانوئل اودیوکو✏️
کتابخانه Reactive Extensions برای جاوا اسکریپت یا RxJS به دلیل اینکه یک کتابخانه برنامه نویسی واکنشی است که از Observables استفاده می کند مشهور است. اگر این برای شما منطقی نیست، نگران نباشید – به همین دلیل است که این راهنما مرتبط است.
در این راهنمای پذیرش، با ویژگیها، مزایا و موارد دیگر RxJS آشنا میشویم تا به شما کمک کنیم بفهمید چیست، چگونه کار میکند و چرا باید از آن استفاده کنید. در پایان این راهنما، میتوانید تشخیص دهید که چه زمانی و چگونه آن را به طور مؤثر در پروژههای خود بپذیرید.
مقدمه ای بر RxJS
در حدود سال 2011، تیم برنامهنویسی ابری مایکروسافت نیاز داشت تا رویدادها را در بخشهای مختلف یک برنامه بهتر مدیریت کند. این نیاز باعث ایجاد پروژه ای به نام Volta شد، یک مجموعه ابزار آزمایشی با هدف ساده سازی توسعه برنامه های کاربردی وب چند لایه.
RxJS بخشی از این پروژه بود. لوگوی آن، که دارای یک مارماهی الکتریکی است، اشاره ای به ولتا است. در همین حال، «افزونهها» به فناوری دیگری به نام افزونههای موازی توسعهیافته در همان زمان اشاره دارد که به خوبی کتابخانه پسوندهای واکنشی (Rx) را تکمیل میکند.
اولین نسخه Rx برای چارچوب دات نت ساخته شد و در 21 ژوئن 2011 منتشر شد. بعداً، تیم پیاده سازی Rx را برای جاوا اسکریپت، RxJS، همراه با نسخه هایی برای زبان های دیگر مانند C++ ایجاد کرد. در اواخر سال 2012، RxJS به عنوان نرم افزار منبع باز، ابتدا در CodePlex منتشر شد و بعداً به GitHub منتقل شد.
شروع کار با RxJS
راستش برنامه نویسی واکنشی به خصوص در ابتدا آسان نیست. با این حال، هر چه بیشتر با آن کار کنید دشوارتر می شود، بنابراین شروع هر چه زودتر می تواند مفید باشد.
برای شروع، به درک نکات زیر نیاز دارید:
- اصول جاوا اسکریپت – این شامل درک نحوه اعلان و فراخوانی توابع، و همچنین آگاهی از نحوه مدیریت رویدادها در جاوا اسکریپت با استفاده از شنوندگان رویداد است. آشنایی با
try...catch
بلوک ها نیز کارایی شما را افزایش می دهند - جاوا اسکریپت ناهمزمان – شما باید اصول اولیه تماسهای برگشتی را بدانید و Promise API از جمله نحوه ایجاد و مصرف وعدهها را بدانید. درک خوب در مورد نحوه استفاده از async و انتظار برای مدیریت عملیات ناهمزمان نیز بسیار قدردانی خواهد شد.
- RxJS نصب شده است – مراحل زیر را برای راهنمایی شما بررسی کنید
برای نصب RxJS، یک دایرکتوری جدید ایجاد کنید. به خاطر این آموزش، می توانید آن را نام ببرید RxJs-Guide
. به داخل آن بروید، ترمینال را باز کنید و با اجرای این دستور یک پروژه Node جدید را مقداردهی اولیه کنید:
npm init -y
در مرحله بعد باید RxJS را نصب کنیم. برای انجام این کار، باید این دستور را اجرا کنید:
npm install rxjs
بیشتر خواندن:
RxJS چیست؟
در برنامه های نرم افزاری، وابستگی زیادی به عملیات ناهمزمان وجود دارد که شامل واکشی داده ها از API ها می شود. RxJS شیوه برخورد ما با این داده ها را متحول کرده است – به ما این امکان را می دهد تا با ارائه ابزارهایی برای دستکاری داده های ناهمزمان، با داده ها مانند جریان ها رفتار کنیم. این ابزارها عبارتند از Observables، Observers، Operators، Subscriptions، Subjects و Schedulers.
بعداً با جزئیات بیشتری به نحوه عملکرد RxJS خواهیم پرداخت، اما در حال حاضر به عنوان یک تشبیه سریع، میتوانید آن را به عنوان یک سرویس پخش زنده ورزشی محلی شخصی در نظر بگیرید.
در این سرویس، Observables یا جریان های داده، کانال های پخش هستند، در حالی که ناظران، بینندگانی هستند که برای دریافت رویدادهای زنده در این کانال ها مشترک می شوند. هنگامی که بیننده مشترک می شود، بلافاصله شروع به دریافت پخش می کند و می تواند در هر زمان اشتراک خود را لغو کند تا آن را متوقف کند.
اپراتورها به عنوان فیلترهایی برای سفارشی کردن پخش عمل می کنند، مانند پرش از تبلیغات یا برجسته کردن لحظات کلیدی. زمانبندها زمان و ترتیب پخشها را مدیریت میکنند، در حالی که Subjects Observableهای ویژهای هستند که پخش یکسانی را با همه بینندگان بهطور همزمان به اشتراک میگذارند و اطمینان حاصل میکنند که همه یک رویداد را در یک زمان میبینند.
ویژگی های کلیدی RxJS که باید بدانید
در بخش قبل، توضیح سادهای درباره نحوه عملکرد RxJS برای ارائه درک سطح بالا بدون گم شدن در جزئیات فنی بررسی کردیم. در ادامه، برخی از اصطلاحات فنی را تعریف میکنیم و به نمونههایی از موارد استفاده از این ویژگیها میپردازیم.
ما این بخش را به دو قسمت تقسیم می کنیم. ابتدا در مورد Observables، Observers و Subscriptions بحث خواهیم کرد و دانش خود را با ساختن یک سیستم RxJS ساده عملی می کنیم. سپس، در مورد اپراتورها، موضوعها و زمانبندها بحث خواهیم کرد و سیستم RxJS خود را با این ویژگیها گسترش میدهیم تا یک مورد استفاده واقعی را نشان دهیم.
قابل مشاهده
احتمالاً در هر تعریف RxJS Observables را پیدا خواهید کرد. اما Observables دقیقا چیست؟
قابل مشاهده ها مانند توابعی هستند که هیچ ورودی دریافت نمی کنند اما می توانند در طول زمان بیش از یک مقدار تولید کنند و آنها را به سمت ناظران سوق دهند. مانند توابع، Observable ها تنبل هستند و باید مشترک شوند.
شباهت هایی بین Observables و the وجود دارد EventEmitter
کلاسی که می تواند باعث شود ما آنها را گیج کنیم، اما عملکرد آنها کمی متفاوت است. یک تفاوت قابل توجه این است که یک EventEmitter
مشتاق است در حالی که Observables تنبل هستند و تا زمانی که در آنها مشترک نشوید شروع به تولید داده نمی کنند.
در اینجا جدولی برای کمک به درک تفاوت بین Observables، توابع و an وجود دارد EventEmitter
در یک نگاه:
تایپ کنید | استراتژی بارگیری | مکانیسم داده | خروجی |
---|---|---|---|
قابل مشاهده | تنبل | فشار دادن | مقادیر چندگانه |
کارکرد | تنبل | کشیدن | ارزش واحد |
Event Emitter | مشتاق | فشار دادن | مقادیر چندگانه |
بیشتر خواندن:
مشاهده کننده
ما در قیاس قبلی خود از Observables به عنوان کانال های پخش به جریان های داده اشاره کردیم. یک جریان یک روش عالی برای توصیف نوع بسته بندی داده های مشاهده پذیر است، زیرا یک مشاهده پذیر مانند کانالی است که داده ها در طول زمان از طریق آن جریان می یابد.
میتوانید این کانال را تماشا کنید و دادههای جدیدی را که وارد میشوند، به صورت همزمان یا ناهمزمان دریافت کنید. به عنوان مثال، این دادهها میتواند جریانی از اعداد، کلیکها یا پیامها باشد که میتوانید هر زمان که قطعه جدیدی وارد میشود به آنها واکنش نشان دهید.
ناظران در عین حال توانایی واکنش به این جریان داده را فراهم می کنند. هر زمان که مقدار یا پیام خطای جدیدی دریافت کنیم، کدی را اجرا می کنند. Observer سه روش را پیاده سازی می کند:
-
next()
هر زمان که مقدار جدیدی منتشر شود توسط Observable فراخوانی می شود -
error()
هر زمان که Observable خطا می دهد فراخوانی می شود -
complete()
هر زمان که Observable انجام شود فراخوانی می شود
توجه داشته باشید که یک Observable ممکن است هرگز تمام نشود، که به دلیل فعالیت کاربر است.
برای مثال، اگر یک Observable در اطراف a پیچیده شده باشد clickListener
در یک دکمه، هر بار که کاربر روی دکمه کلیک می کند، با انتشار یک مقدار یا پرتاب یک خطا واکنش نشان می دهد. شما نمی دانید چه زمانی تمام می شود، زیرا بستگی به زمانی دارد که کاربر کلیک را متوقف کند.
اینجاست که اشتراک ها وارد می شوند. در ادامه ببینیم یک اشتراک در RxJS چگونه کار می کند.
اشتراک، ابونمان
یک اشتراک به Observable اجازه می دهد بداند چه زمانی باید یک متد Observer را فراخوانی کند. با استفاده از subscribe
روش، میتوانیم به Observable بگوییم که Observer به مقادیری که منتشر میکند اهمیت میدهد. شما هم می توانید subscribe
یا unsubscribe
به جریان داده ها
مجموعه نمودارهای زیر به شما کمک می کند تا Observables، Observers و Subscriptions را درک کنید. ابتدا، بیایید ببینیم چگونه یک Observable در اطراف جریانی از مقادیر قرار می گیرد: این نقش Observers را معرفی می کند که برای مدیریت یک مقدار یا بیش از یک مقدار معرفی می شوند:
اشتراک زمانی اتفاق می افتد که Observer شروع به گوش دادن به Observable کند. در این مرحله، Observable شروع به ارسال مقادیر به Observer می کند و باعث می شود
next()
، error()
، و complete()
روشهایی که Observable مقادیر را منتشر میکند، با خطا مواجه میشود یا تکمیل میکند، به ترتیب: همانطور که قبلاً اشاره کردیم، همه مشاهده پذیرها به پایان نمی رسند، اما برخی پایان می یابند.
به عنوان مثال، یک قابل مشاهده که داده ها را از یک API واکشی می کند، پایان می یابد. یک درخواست HTTP GET برای دریافت دادههای کاربر ایجاد میکند، پس از واکشی دادهها را منتشر میکند، و سپس تکمیل میشود و هرگونه انتشار بیشتر را متوقف میکند. در چنین مواردی، complete
متد به طور خودکار پس از واکشی و ارسال داده ها فراخوانی می شود: همچنین میتوانیم جریانی داشته باشیم که در نقطهای از زمان خطا ایجاد کند. به عنوان مثال، زمانی که ما یک درخواست HTTP می کنیم، پاسخی که دریافت می کنیم می تواند یک خطای سمت سرور باشد. در مواردی مانند این، Observable خطا را پرتاب میکند، که ما میتوانیم آن را مدیریت کنیم
error
تابع: اکنون که دیدیم Observables، Observers و Subscriptions چیست، اجازه دهید آنها را به کار بیندازیم. ما در حال ساختن یک سیستم RxJS هستیم که در آن یک Observable داریم که برخی از داده ها را منتشر می کند.
ساختن یک سیستم RxJS با Observables، Observers و Subscriptions
اگر مراحل راهاندازی را در بخش شروع با RxJS ما دنبال کردهاید، باید یک پروژه اولیه را از قبل تنظیم کرده باشید. به دایرکتوری پروژه خود بروید، آن را در هر ویرایشگر کد مورد نظر خود باز کنید – من از VS Code استفاده می کنم – و یک index.js
فایل.
در این فایل ابتدا یک Observable ایجاد می کنیم، سپس یک Observer ایجاد می کنیم و در نهایت آنها را با یک Subscription متصل می کنیم و کد را اجرا می کنیم. با وارد کردن یک RxJS Observable مانند زیر شروع کنید:
const {Observable} = require('rxjs');
بعد، بیایید نمونه سازی کنیم Observable
کلاس و یک تابع برای ایجاد Observable ما به آن ارسال کنید. این تابع یک را می گیرد subscriber
شی به عنوان آرگومان، که برای انتشار مقادیر، رسیدگی به خطاها و تکمیل سیگنال استفاده می شود. به یاد داشته باشید که یک Observable می تواند چندین مقدار را منتشر کند و ما بیش از یک مقدار را منتشر خواهیم کرد. کد به شکل زیر است:
//Create an observable
const observable = new Observable((subscriber) => {
subscriber.next(100);
subscriber.next(200);
subscriber.next(300);
subscriber.complete();
});
اگر به خاطر داشته باشید، Observer یک شی است که اختیاری دارد next()
، error()
، و complete()
مواد و روش ها. ما از این روش ها استفاده خواهیم کرد:
-
next()
مقدار دریافتی را در کنسول ثبت می کند -
error()
خطای دریافتی را در کنسول ثبت می کند -
complete()
گزارش هایی که قابل مشاهده کامل شده است
بیایید اکنون Observer خود را ایجاد کنیم:
//create an Observer
const observer = {
next: (value) => console.log("The observer received a value" + value),
error: (error) => console.log("The observer received an error" + error),
complete: () => console.log('observer is complete')
}
در نهایت، ما باید Observable را با یک اشتراک به Observer متصل کنیم:
//connect the observable and the observer
observable.subscribe(observer);
این خط واحد را صدا می کند subscribe
متد روی Observable است و Observer را به عنوان آرگومان ارسال می کند. هنگامی که Observable مشترک شد، شروع به انتشار مقادیر می کند. وقتی ما اجرا می کنیم node index.js
دستور، مقادیر ثبت شده در زیر را خواهیم داشت: اکنون که مفهوم اصلی را نشان دادیم، بیایید یک سناریوی واقعیتر را امتحان کنیم که شامل کاری است که ممکن است هر از چند گاهی به عنوان توسعهدهنده انجام دهیم. ما می خواهیم که Observer ما داده های کاربر را منتشر کند تا بتوانیم دسترسی به برنامه خود را برای کاربران فعال 18 ساله و بالاتر محدود کنیم:
data: [
{
status: "inactive",
name: "John",
age: 17
},
{
status: "active",
name: "Jane",
age: 25
},
{
status: "inactive",
name: "Joe",
age: 16
},
{
status: "active",
name: "Jill",
age: 35
},
{
status: "active",
name: "Jack",
age: 45
},
{
status: "inactive",
name: "Jill",
age: 35
},
{
status: "active",
name: "Jill",
age: 12
}
]
این ما را به اپراتورها، زمانبندیها و موضوعات در RxJS میبرد. بیایید این اصطلاحات را تعریف کنیم و درک درستی از نحوه اعمال آنها در پروژه آزمایشی خود داشته باشیم.
اپراتورها
اپراتورها برای نوشتن کدهای ناهمزمان پیچیده به شیوه ای واضح و شفاف بسیار مهم هستند. ما می توانیم از عملگرها برای دستکاری Observables استفاده کنیم. آنها به دو صورت می آیند:
- اپراتورهای Pipeable: این عملگرها توابعی هستند که می توان با استفاده از آن به یکدیگر زنجیره زد
.pipe()
روش روی یک مشاهده پذیر مثالها عبارتند ازmap
،filter
، وmergeMap
. اپراتورهای Pipeable یک Observable را به عنوان ورودی می گیرند و یک Observable جدید را برمی گردانند که امکان تبدیل جریان داده انعطاف پذیرتر را فراهم می کند. - اپراتورهای ایجاد: این عملگرها Observableهای جدید را از منابع مختلف مانند رویدادها، تایمرها یا دیگر ساختارهای داده ایجاد می کنند. مثالها عبارتند از
of
،from
، وinterval
. ما می توانیم از این عملگرها برای تولید Observables از ابتدا استفاده کنیم و زمینه را برای پردازش جریان داده ها فراهم کنیم
همانطور که در بالا ذکر شد، ما می خواهیم پروژه آزمایشی خود را به روز کنیم تا کاربران غیرفعال و زیر 18 سال را فیلتر کنیم. ابتدا باید داده های کاربر را منتشر کنیم، بنابراین منبع داده را همانطور که در زیر مشاهده می کنید دریافت می کنیم:
const users = {
data: [
{
status: "inactive",
name: "John",
age: 17
}, //fill in the remaining data...
]
}
در مرحله بعد، داده های کاربر را برای مشترکین ارسال می کنیم:
const observable = new Observable((subscriber) => {
subscriber.next(users.data);
subscriber.complete();
})
برای فیلتر کردن کاربران بر اساس فعالیت و سن آنها، باید آن را وارد کنیم map
و filter
عملگرها از RxJS و اعمال آنها بر روی Observable با استفاده از .pipe()
روش. استفاده خواهیم کرد map
برای تبدیل داده های منتشر شده توسط مشاهده پذیر، و filter
اپراتور برای حذف مشروط کاربرانی که معیارهای مشخص شده را ندارند:
const observable = new Observable((subscriber) => {
subscriber.next(users.data);
subscriber.complete();
}).pipemap(users => users.filter(user => (user.status === 'inactive' && user.age 18)))
برای مشاهده نتیجه، Observer بعدی را با این جایگزین کنید:
next: (value) => console.log("The observer received active users" + JSON.stringify(value,null, 2))
و کد را اجرا کنید:
بیشتر خواندن:
فاعل، موضوع
سوژه ها انواع خاصی از Observables هستند که می توانند چندپخشی باشند، به این معنی که بیش از یک ناظر می توانند مشترک یک موضوع واحد شوند. در مقابل، مشاهدهپذیرهای معمولی فقط میتوانند یکپارچه باشند و یک رابطه یک به یک بین مشاهدهپذیر و مشاهدهکنندگان آن داشته باشند.
هر موضوعی هم ناظر و هم قابل مشاهده است. این ماهیت دوگانه به سوژهها اجازه میدهد نه تنها دادهها را دریافت کنند (مانند مشاهدهگر) بلکه دادهها را نیز منتشر کنند (مانند یک مشاهدهپذیر).
سوژه ها می توانند چندپخشی باشند، که می تواند در سناریوی دنیای واقعی ما مهم باشد. فرض کنید چندین بخش از برنامه خود دارید که باید به لیست فیلتر شده کاربران واکنش نشان دهند. یک موضوع به شما امکان می دهد نتایج فیلتر شده را برای همه مشترکین چندپخش کنید.
برای استفاده از یک موضوع در RxJS، باید این ماژول ها را وارد کنید:
const { Subject } = require('rxjs');
const { map } = require('rxjs/operators');
این نقشه راه یا جریان اجرایی است که برای اجرای Subjects استفاده خواهیم کرد:
- ايجاد كردن
userSubject
- تعريف كردن
observer1
وobserver2
- مشترک شدن هر دو ناظر در
userSubject
با لوله ای که کاربران را فیلتر می کند -
userSubject.next(users.data)
داده های کاربر را منتشر می کند - هر دو مشاهده کننده لیست فیلتر شده کاربران غیرفعال زیر 18 سال را دریافت می کنند
-
userSubject.complete()
فراخوانی می شود و به هر دو ناظر اطلاع داده می شود که جریان کامل شده است
در اینجا نحو برای ایجاد یک است userSubject
:
const userSubject = new Subject();
در این مورد، userSubject
نمونه جدیدی از a است Subject
. ما از آن برای ارسال دادههای کاربر به دو مشاهدهگر خود استفاده میکنیم که میتوانیم آنها را به این صورت ایجاد کنیم:
const observer1 = {
next: (value) => console.log("Observer 1 received: " + JSON.stringify(value, null, 2)),
error: (error) => console.log("Observer 1 received an error: " + error),
complete: () => console.log('Observer 1 is complete')
};
const observer2 = {
next: (value) => console.log("Observer 2 received: " + JSON.stringify(value, null, 2)),
error: (error) => console.log("Observer 2 received an error: " + error),
complete: () => console.log('Observer 2 is complete')
};
سپس باید ناظران خود را در موضوع مشترک کنیم:
userSubject.pipe(
map(users => users.filter(user => user.status === 'inactive' && user.age 18))
).subscribe(observer1);
userSubject.pipe(
map(users => users.filter(user => user.status === 'inactive' && user.age 18))
).subscribe(observer2);
در نهایت، ما داده ها را منتشر می کنیم و موضوع را تکمیل می کنیم:
userSubject.next(users.data);
userSubject.complete();
با استفاده از یک موضوع، میتوانیم اطمینان حاصل کنیم که همه مؤلفهها یا جریانهایی که نیاز به نمایش دادههای فیلتر شده دارند، هر زمان که منبع داده اصلی تغییر کند، همان دادههای بهروزرسانی شده را دریافت میکنند.
بیشتر خواندن:
برنامه ریزان
تا اینجا ما Observables، Observers، Subscriptions، Operators و Subjects را دیده ایم. آخرین ویژگی که در مورد آن بحث خواهیم کرد، Schedulers است.
ما یاد گرفتیم که Subscriptions Observables و Observer را به هم متصل می کند، اما Schedulers اجرای این اشتراک ها را مدیریت می کند. یک Scheduler زمان شروع اجرای Observables و زمان تحویل مقادیر به Observer را کنترل می کند.
بیایید با استفاده از یک مثال ساده کمی Schedulers را تجزیه کنیم. در جاوا اسکریپت، وظایف به میکرووظیفه ها و ماکروتسک ها طبقه بندی می شوند که بر ترتیب اجرای آنها در حلقه رویداد تأثیر می گذارد. تصور کنید چندین کار با اولویت بالا (وظیفه های کوچک) و معمولی (macrotasks) برای تکمیل در یک روز دارید:
-
Regular log
: یک تماس تلفنی سریع که بلافاصله شروع می کنید -
process.nextTick
: پیامک فوری که به محض قطع کردن تلفن به آن پاسخ می دهید -
Promise.resolve
: ایمیلی با اولویت بالا که بلافاصله بعد از متن فوری ارسال می کنید -
setTimeout
: یک استراحت ناهار برای بعد از کارهای فوری برنامه ریزی شده است -
setImmediate
: یک استراحت چای بعد از ظهر که بعد از انجام تمام کارهای برنامه ریزی شده دیگر اتفاق می افتد
وظایفی مانند process.nextTick
و Promise.resolve()
وظایف خرد هستند و بلافاصله انجام می شوند. در همین حال، وظایف ماکرو مانند setTimeout
و setImmediate
برای مدتی بعد برنامه ریزی می شوند و اطمینان حاصل می شود که کارهای منظم پس از کارهای با اولویت بالا تکمیل می شوند:
// Regular console log
console.log('Regular log');
// setTimeout
setTimeout(() => console.log('setTimeout'), 0);
// Promise.resolve
Promise.resolve().then(() => console.log('Promise.resolve'));
// setImmediate
setImmediate(() => console.log('setImmediate'));
// process.nextTick
process.nextTick(() => console.log('process.nextTick'));
اگر کد بالا را اجرا کنید، نتیجه به شکل زیر خواهد بود:
Regular log
process.nextTick
Promise.resolve
setTimeout
setImmediate
اکنون، جریانها در RxJS میتوانند همزمان و ناهمزمان باشند. بنابراین اگر بخواهیم کنترل کنیم که جریان های ما در چه زمینه ای اجرا می شوند چه؟ زمانبندیهای کلیدی برای این کار وجود دارد که عبارتند از:
-
asyncScheduler
– Observables را به صورت ناهمزمان اجرا می کند -
queueScheduler
– Observables را به صورت همزمان در یک صف اجرا می کند -
animationFrameScheduler
– وظایف را قبل از فریم انیمیشن مرورگر بعدی برنامه ریزی می کند
برای ادغام یک Scheduler، از observeOn
و subscribeOn
اپراتورها به ترتیب Scheduler را برای مشاهده و اشتراک مشخص کنند. در اینجا نحوه ادغام یک Scheduler به صورت همزمان آورده شده است:
const { of, queueScheduler } = require('rxjs');
const { observeOn } = require('rxjs/operators');
// Synchronous task with queueScheduler
of('Synchronous task').pipe(
observeOn(queueScheduler)
).subscribe(value => console.log(value));
و در اینجا نحوه ادغام یک Scheduler به صورت همزمان آورده شده است:
const { of, asyncScheduler } = require('rxjs');
const { observeOn } = require('rxjs/operators');
// Asynchronous task with asyncScheduler
of('Asynchronous task').pipe(
observeOn(asyncScheduler)
).subscribe(value => console.log(value));
مزایا و معایب RxJS
قبلاً ویژگیهای RxJS را برجسته کردهام، اما میخواهم چند دلیل را توضیح دهم که چرا فکر میکنم این یک انتخاب عالی است. برای کمک به ارزیابی منصفانه آن، من همچنین در مورد برخی از ملاحظات که باید در نظر داشته باشید صحبت خواهم کرد.
کارایی
به طور کلی، RxJS بسیار سریع است، اما عملکرد آن می تواند بر اساس نحوه نوشتن و مدیریت کد، به ویژه در مورد اشتراک ها و ساختارهای پیچیده قابل مشاهده متفاوت باشد. اپراتورها برای کارایی بالا طراحی شده اند، اما با این وجود، خوب است به خاطر داشته باشید که اجرای کد کمتر همیشه سریعتر از کد بیشتر خواهد بود.
سهولت استفاده، DX و منحنی یادگیری
ممکن است کمی طول بکشد تا سر خود را به دور RxJS بپیچید و تجربه بودن شما را از منحنی یادگیری شیب دار آن معاف نمی کند.
برای استفاده مؤثر از RxJS در پروژههای دنیای واقعی، باید از نمونههای اولیه نشان داده شده در این وبلاگ فراتر بروید. بسیاری از توسعه دهندگان به این حد نمی رسند، که قابل درک است، زیرا نامگذاری اپراتورها و خود اپراتورهای پیشرفته می تواند بسیار خسته کننده باشد.
با این حال، هنگامی که اصول RxJS را درک کنید و شروع به استفاده از آن کنید، همه چیز بسیار ساده تر می شود. شما شروع به قدردانی خواهید کرد که RxJS چگونه کارآمد است. اگر بتوانید منحنی یادگیری را پشت سر بگذارید، RxJS میتواند ابزار قدرتمندی برای اهرمسازی باشد.
اندازه بسته
RxJS v7 نسبت به نسخه قبلی خود کاهش قابل توجهی در اندازه دارد. اگر برنامه شما از تمام اپراتورهای RxJS v6 استفاده می کرد، به 52 کیلوبایت نیاز داشت. با این حال، با نسخه 7، این مقدار به 19 کیلوبایت کاهش می یابد.
چه این شما را تحت تأثیر قرار دهد یا نه، مهم است به خاطر داشته باشید که در مناطقی با اتصالات اینترنتی بسیار بد، هر کیلوبایت ذخیره شده می تواند به طور قابل توجهی بر عملکرد و UX تأثیر بگذارد.
جامعه و اکوسیستم ها
RxJS دارای یک جامعه قوی با بیش از 11.2 میلیون کاربر، 500 مشارکت کننده و 30 هزار ستاره در Github است. این اعداد یک جامعه فعال با پشتیبانی از React، Angular، Vue و SolidJS در اکوسیستم جاوا اسکریپت را نشان میدهند.
با این سطح از پشتیبانی جامعه، بعید است که با مشکلاتی روبرو شوید که قبلاً به صورت آنلاین حل نشده است. در نتیجه، با وجود منحنی یادگیری تا حدودی شیب دار، شما منابع زیادی در سفر خود با استفاده از RxJS دارید.
مستندات
اسناد RxJS راه زیادی را در جزئیات هر چیزی که برای پیادهسازی اپراتورهای خود لازم است انجام میدهند، که بسیار مهم است زیرا بیش از 100 اپراتور دارد که هر کدام برای انجام وظایف خاصی روی Observables طراحی شدهاند.
با وجود داشتن بیش از 100 اپراتور برای استفاده، بر اساس تجربه شخصی، به احتمال زیاد فقط باید حدود 50 یا کمتر را بدانید و از 25 مورد از آن ها در پروژه های خود استفاده کنید. البته، این موضوع به موارد استفاده خاص شما بستگی دارد، اما به داشتن اسناد دقیقی کمک می کند که به وضوح توضیح دهند که کدام یک، چرا، و چگونه باید استفاده شود.
ادغام با سایر کتابخانه ها و چارچوب ها
ادغام RxJS با کتابخانه ها و چارچوب های مختلف جاوا اسکریپت نسبتاً ساده است. در Angular، RxJS داخلی است و معمولاً برای مدیریت عملیات ناهمزمان استفاده می شود. RxJS همچنین با React، Node.js، Vue، Svelte و SolidJS ادغام می شود.
اگرچه RxJS ممکن است همیشه گزینه مناسب یا جایگزین کاملی برای کتابخانههای خاص نباشد – مانند React Query، راهی برای مدیریت واکشی ناهمزمان داده در React – هنوز برای بسیاری از سناریوهای دیگر مناسب است. اما در سراسر اکوسیستم جاوا اسکریپت، RxJS قابلیت های قدرتمندی را برای مدیریت وظایف پیچیده ناهمزمان و برنامه نویسی واکنشی فراهم می کند.
اشکال زدایی
اشکال زدایی در RxJS شامل استفاده از ابزارهایی مانند عملگر tap برای ثبت مقادیر قابل مشاهده و ایجاد عملگرهای اشکال زدایی سفارشی برای سطوح ثبت انعطاف پذیر است. این رویکرد به شناسایی زودهنگام مشکلاتی مانند نشت حافظه و اشتراکهای متعدد کمک میکند و قابلیت نگهداری کد و نظارت بر عملکرد را افزایش میدهد.
در حالی که اشکال زدایی می تواند کمی استرس زا باشد، این مشکل فقط برای RxJS نیست. RxJS در طول سالها تکامل یافته است، و اگرچه ممکن است این تجربه در همه فریمورکها روان نباشد، مزایای آن ممکن است ارزش سرمایهگذاری برای یادگیری را داشته باشد.
از موارد برای RxJS استفاده کنید
RxJS بسیار متنوع است. در اینجا فقط چند نمونه از موارد استفاده آورده شده است، با آموزش های مرتبط اگر می خواهید جزئیات بیشتری را بررسی کنید:
- مدیریت حالت در React: میتوانید RxJS را با React Hooks برای مدیریت حالت ادغام کنید و یک رویکرد عملکردی و واکنشی برای مدیریت تغییرات حالت و جریانهای داده ناهمزمان ارائه دهید.
- تبدیل داده ها در TypeScript: RxJS برای تبدیل جریان های داده در TypeScript بسیار موثر است و به توسعه دهندگان این امکان را می دهد تا تغییرات و دستکاری های پیچیده را روی داده های قابل مشاهده اعمال کنند.
- ساختن یک برنامه جستجوی ویدیوی YouTube: میتوانید از RxJS برای ساخت یک برنامه استریم استفاده کنید، که قدرت آن را در مدیریت درخواستهای HTTP ناهمزمان و بهروزرسانی واکنشی رابط کاربری نشان میدهد.
فراتر از این، RxJS یک گزینه عالی برای هر گونه برنامه نویسی واکنشی و نیازهای مدیریت دولتی است.
RxJS در مقابل Bacon.js در مقابل سیگنال
در این بخش، جایگزین های فرضی RXJS را با هم مقایسه می کنیم و نقاط قوت آنها را نیز برجسته می کنیم.
شاخص | RxJS | Bacon.js | سیگنال ها |
---|---|---|---|
امکانات | برنامه نویسی واکنشی با مشاهده پذیرها، مجموعه ای غنی از عملگرها، از رویدادهای ناهمزمان و جریان های داده پشتیبانی می کند. | بسیار شبیه به RxJS با این تفاوت که دو نوع Observable وجود دارد – EventStream و Property | مدیریت حالت واکنشی برای Angular. بر واکنش پذیری و تشخیص تغییر تمرکز می کند. به طور یکپارچه با اکوسیستم Angular ادغام می شود |
کارایی | در صورت استفاده صحیح عملکرد بالایی را ارائه می دهد. به مدیریت اشتراک ها و Observable ها بستگی دارد | سابقه عملکرد خوبی دارد | بهینه شده برای برنامه های Angular، عملکرد را با کاهش چرخه های تشخیص تغییر بهبود می بخشد، و در مدیریت حالت واکنش بسیار کارآمد است. |
انجمن | جامعه بزرگ و فعال با پشتیبانی گسترده از اکوسیستم های مختلف جاوا اسکریپت. | جامعه در حال رشد، با بیش از 86 مشارکتکننده و 6.5 هزار ستاره | انجمن Angular به طور فعال سیگنال ها را حفظ کرده و قویاً پشتیبانی می کند |
اسناد/منابع | [Comprehensive documentation](https://rxjs.dev/guide/overview)، آموزش ها و نمونه های زیادی در همه جا به صورت آنلاین موجود است. یکی از کتابخانه های واکنشی که بیشترین پشتیبانی را دارد | خیلی [bogus documentation](https://github.com/baconjs/bacon.js)، اما موارد استفاده API با جزئیات خوبی دارد | بسیار مفصل [documentation](https://github.com/angular/angular/discussions/49685) و مثال |
چارچوب ها | React، Angular و فریمورک های دیگر | فریمورک های سازگار با TypeScript مانند Angular، React (با TypeScript) و Vue.js (با TypeScript) | مخصوص Angular |
با توجه به مقایسه ما، RxJS در مدیریت عملیات ناهمزمان پیچیده و جریان های داده برتری دارد. در همین حال، Bacon.js همچنین بر مدیریت عملیات ناهمزمان پیچیده، به ویژه در اکوسیستم React تمرکز دارد. در نهایت، سیگنال یک رویکرد کاربردی برای مدیریت برنامههای ناهمزمان و واکنشپذیر مخصوص Angular ارائه میکند.
بیشتر خواندن:
نتیجه
پذیرش RxJS امروز به طور قابل توجهی توانایی شما را برای مدیریت عملیات ناهمزمان و ساخت برنامه های واکنشی بهبود می بخشد. با دانش درست در این مقاله، دلیل کافی برای استفاده از RxJS دارید. امروز RxJS را امتحان کنید!
آیا کتابخانه های جدید JS را برای ایجاد ویژگی های جدید یا بهبود عملکرد اضافه می کنید؟ اگر برعکس عمل کنند چه؟
شکی نیست که فرانت اندها پیچیده تر می شوند. همانطور که کتابخانه های جدید جاوا اسکریپت و وابستگی های دیگر را به برنامه خود اضافه می کنید، برای اطمینان از اینکه کاربران شما با مشکلات ناشناخته مواجه نمی شوند، به دید بیشتری نیاز دارید.
LogRocket یک راه حل مانیتورینگ برنامه کاربردی است که به شما امکان می دهد خطاهای جاوا اسکریپت را به گونه ای تکرار کنید که گویی در مرورگر شما اتفاق افتاده است تا بتوانید به طور موثرتری به باگ ها واکنش نشان دهید.
LogRocket بدون در نظر گرفتن چارچوب، با هر برنامه ای کاملاً کار می کند و دارای پلاگین هایی برای ثبت زمینه اضافی از Redux، Vuex، و @ngrx/store است. به جای حدس زدن چرایی مشکلات، می توانید در مورد وضعیتی که برنامه شما در هنگام بروز مشکل در آن قرار داشت، جمع آوری کرده و گزارش دهید. LogRocket همچنین عملکرد برنامه شما را نظارت می کند، معیارهایی مانند بار CPU مشتری، استفاده از حافظه مشتری و موارد دیگر را گزارش می دهد.
با اطمینان بسازید – نظارت را به صورت رایگان شروع کنید.