در مقاله قبلی در مورد RxJS با کلیات و اصول RxJS آشنا شدیم. متوجه شدیم که Subject نوع خاصی از Observable است و اتفاقات یا مقادیر تغییر یافته را انتقال میدهد، با این تفاوت که میتواند چند مصرف کننده (consumer) را بپذیرد و به لیستی از مصرف کننده ها اطلاع دهد. به عبارت ساده تر multicast است.
اما کتابخانه RxJS انواع مختلفی از Subject را ارائه کرده است که در این مقاله میخواهیم به تفاوت بین آنها بپردازیم.
چهار نوع Subject در کتابخانه RxJS وجود دارد:
Void Subject
BehaviorSubject
ReplaySubject
AsyncSubject
در ادامه به هر یک از این چهار نوع Subject میپردازیم
نوع اول: Void Subject
این نوع Subject دربرگیرنده امکانات عمومی همه Subject هاست. تنها تفاوت Subject با Observable این است که میتواند با دریافت مقدار جدید، بجای یک observer، لیستی از observer ها را خبردار کند.
مثال زیر را مرور کنیم:
نوع Subject شامل حداقل امکانات همه Subject هاست و شامل موارد زیر است:
با تابع subscribe می توان تابعی را جهت دریافت تغییرات رزرو کرد.
با تابع next میتوان مقادیر جدید را به observer ها رساند.
با تابع complete میتوان همه رزروها را بست.
نوع دوم: BehaviorSubject
این نوع subject با مقدار اولیه صدا زده میشود و همواره به مقدار فعلی آگاه است. به دو صورت می توانیم به مقدار فعلی این subject دسترسی پیدا کنیم. روش اول استفاده از value property است. روش دوم استفاده از متد subscribe است.
مثال زیر بیانگر رفتار BehaviorSubject است:
در مثال بالا:
ابتدا یک آبجکت subject با مقدار اولیه صفر ساخته میشود.
به محض اینکه تابع subscribe را صدا کنید، مقدار فعلی برگردانده میشود و مقدار صفر توسط تابع رجیستر شده (observerA) لاگ میشود.
مقدار فعلی subject به یک تغییر میکند و در کنسول (observerA) لاگ میشود.
مقدار فعلی subject به دو تغییر میکند و در کنسول (observerA) لاگ میشود.
به محض اینکه برای بار دوم تابع subscribe صدا زده میشود، مقدار دو در تابع جدید (observerB) در کنسول لاگ میشود.
سپس مقدار فعلی subject توسط value property دریافت شده و در کنسول لاگ میشود
در نهایت مقدار فعلی subject به سه تغییر کرده و دوبار در کنسول لاگ میشود.
نوع سوم: ReplaySubject
فرق این نوع Subject با BehaviorSubject این است که نه تنها به مقدار فعلی آگاه است، بلکه لیست مشخصی از تغییرات قبلی را نیز نگه میدارد. ساخت ReplaySubject نیاز به مقدار ورودی buffer دارد. یعنی تعداد تغییراتی که نگه میدارد. این مقدار مشخص میکند بلافاصله بعد از subscribe، چه تعداد تغییر را به observer پاس بدهد. مثلا اگر مقدار 3 را به عنوان ورودی پاس بدهیم، مقدار فعلی و دو تغییر قبل در صورت وجود، برمیگردد.
مثال زیر را با هم مرور کنیم:
ابتدا یک ReplaySubject با مقدار بافر 2 ساخته میشود. یعنی به محض subscribe، علاوه بر مقدار فعلی، یک تغییر قبل هم در صورت وجود برمیگردد.
یک تابع subscribe میکند و هنوز مقداری در بافر subject ذخیره نشده است . پس چیزی لاگ نمیشود.
مقدار فعلی به یک تغییر میکند و تابع مطلع میشود.
مقدار فعلی به دو تغییر میکند و تابع مطلع میشود.
مقدار فعلی به سه تغییر میکند و تابع مطلع میشود.
یک تابع جدید subscribe میکند. به محض subscribe شدن، دو مقدار آخر ( ابتدا 2 و سپس 3 ) به ترتیب به تابع جدید اطلاع داده میشود.
سپس مقدار فعلی به 4 تغییر میکند و هر دو تابع مطلع میشوند.
سپس مقدار فعلی به 5 تغییر میکند و هر دو تابع مطلع میشوند.
پارامتر ورودی windowTime:
این نوع subject پارامتر ورودی دومی هم دارد بنام windowTime که از نوع زمان و برحسب میلی ثانیه است. این پارامتر تعیین میکند که به محض subscribe، بخشی از تغییرات (حداکثر به اندازه بافر) که زمان تغییر آنها برابر یا کمتر از windowTime بوده، برگردد. مثلا اگر مقدار 500 به عنوان windowTime به ReplaySubject پاس داده شود، به محض subscribe یک observer جدید، تغییراتی برگردانده میشود که 500 میلی ثانیه قبل یا دیرتر اتفاق افتاده باشند:
نوع چهارم: AsyncSubject
این نوع Subject تنها مقدار فعلی را برمیگرداند و زمانی برمیگرداند که complete شده باشد. پس از complete شدن، هیچ مقدار جدیدی را نمی پذیرد و همان آخرین مقدار را برمیگرداند.
مثال زیر به خوبی کارکرد AsyncSubject را توضیح میدهد:
مثال بالا را خط به خط بررسی کنیم:
ابتدا یک instance از AsyncSubject میسازیم.
تابع اول را رجیستر میکنیم (ObserverA)
مقدار فعلی به یک تغییر میکند ولی اتفاقی نمی افتد.
مقدار فعلی به دو، سه و چهار تغییر میکند و اتفاقی نمی افتد.
تابع دوم هم رجیستر میشود (observerB)
مقدار فعلی به 5 تغییر میکند.
تابع complete صدا زده میشود و به همه توابع فعلی که رجیستر کرده اند، مقدار 5 (آخرین مقدار) ارسال می شود.
به محض اینکه یک تابع جدید (ObserverC) رجیستر شود، چون بعد از complete شدن رجیستر کرده است، مقدار 5 به آن ارسال میشود.
تابع next صدا زده میشود و مقدار 6 به آن ارسال میشود. اما مقدار 5 باقی می ماند و تغییری نمیکند. هر تابع دیگری هم subscribe کند، همان مقدار 5 برگردانده میشود.
نتیجه:
به صورت کلی :
از Subject زمانی استفاده کنید که منتظر اتفاقات آینده هستید.
از BehaviorSubject زمانی استفاده کنید که فقط مقدار فعلی را نیاز دارید.
از ReplaySubject زمانی استفاده کنید که لیستی از تغییرات یا بازه زمانی مشخصی از تغییرات نیاز دارید.
از AsyncSubject زمانی استفاده کنید که فقط آخرین تغییر را نیاز دارید.