Angular 5.x به همراه پشتیبانی از RxJS 5.5.x منتشر شدهاست. RxJS 5.5 نیز به همراه تغییر قابل ملاحظهای در نحوهی import اجزای آن توسط ویژگی جدید lettable operators است. در این مطلب نحوهی ارتقاء برنامههای قبلی به این نگارش جدید و همچنین اثر آنرا بر اندازهی برنامهی نهایی تولید شده، بررسی میکنیم.
روش جدید import اجزای RxJS در نگارش 5.5 آن
تغییرات تعاریف عملگرها:
تا پیش از Angular 5 و RxJS 5.5 (و یا Angular CLI versions <1.5.0)، اگر نیاز به عملگری (operator/function) مانند map وجود داشت، روش import آن به صورت زیر بود:
import 'rxjs/add/operator/map';
اما پس از RxJS 5.5 امکان import آنها
با روش مخصوص ES 6 میسر شدهاست (به نام جمع operators دقت داشته باشید؛ چون مسیر rxjs/observable نیز وجود دارد):
import { map } from 'rxjs/operators';
بنابراین در این حالت دیگر روش import یکجای این تعاریف در فایلی مانند «
rxjs-operators.ts» وجود ندارد و این تعاریف باید به ازای هر فایلی که از آنها استفاده میکنند، مانند سایر importهای ES 6 یکبار دیگر مجددا ذکر شوند؛ مانند:
import { map, catchError, tap } from 'rxjs/operators';
در حالت کلی مسیر node_modules/rxjs/operators را برای یافتن متدهای جدید بررسی کنید.
همچنین در این نگارش، Observable بجای rxjs/Rx :
import { Observable } from 'rxjs/Rx';
از rxjs/Observable دریافت میشود:
import { Observable } from 'rxjs/Observable';
تا بتوان از قابلیتهای جدید آن استفاده کرد.
تغییرات تعاریف statics:
برای صدور خطاها بجای throw قبلی:
import 'rxjs/add/observable/throw';
Observable.throw('error');
خواهیم داشت:
import { ErrorObservable } from 'rxjs/observable/ErrorObservable';
ErrorObservable.create('error');
و برای ایجاد تایمر، بجای timer پیشین:
import "rxjs/add/observable/timer";
const timerSource$ = Observable.timer(initialDelay);
خواهیم داشت:
import { timer } from 'rxjs/observable/timer';
const timerSource$ = timer(initialDelay);
و به طور کلی مسیر node_modules\rxjs\observable را برای یافتن تعاریف static قبلی جستجو کنید.
معرفی lettable operators Lettable Operators توابعی هستند که یک observable را دریافت و یک observable را بازگشت میدهند؛ به آنها pipeable operators هم میگویند. از این جهت که در اینجا متد جدید pipe، برای ترکیب چندین تابع عملگر بر روی مقادیر observable توسط آن، ارائه شدهاست.
مزیت این روش این است که pipeable/lettable operators، یک سری تابع محض هستند و اگر مورد استفاده قرار نگیرند، به سادگی توسط سیستم و ابزار ساخت برنامه، از فایل نهایی حذف خواهند شد؛ یا اصطلاحا tree-shakable هست. اما روش پیشین تعریف این عملگرها، tree-shakable نبوده و حتی اگر توسط برنامه مورد استفاده قرار نگیرند، در بستهی نهایی تولید شده، حضور خواهند داشت. Tree-shaking به معنای پروسهی حذف کدهای مرده است. روش جدید استفادهی از importهای ES 6، امکان تشخیص عملگرهای استفاده نشده را توسط ابزارهایی مانند TS-Lint و
تنظیمات کامپایلر TypeScript به سادگی میسر میکنند و به این ترتیب با حذف متدها و ماژولهای استفاده نشده، میتوان به حجم نهایی بسیار کمتری رسید.
روش قبلی تعریف عملگرهای Observable، اصطلاحا Patching نامیده میشود. به این معنا که هر متد جدید import شدهی در برنامه، به Observable.prototype اصلی اضافه و وصله میشود. اما در این روش جدید، تنها متد وصله شدهی از پیش موجود، Observable.prototype.pipe است و تمام متدهای دیگر import شده، توابع محض هستند و نه وصلهای به Observable.prototype اصلی. زمانیکه وصلهای به Observable.prototype متصل میشود، دیگر امکان حذف آن توسط ابزارهای ساخت برنامه وجود ندارد (حتی اگر استفاده نشده باشند)؛ اما اگر این متدها به صورت خالص و مجزای از Observable.prototype ارائه شوند، امکان حذف کدهای مرده و استفاده نشده، به سادگی میسر خواهد شد؛ چون توابعی خالص و متکی به خود هستند.
یک نمونه مثال استفادهی از pipeable/lettable operators را در کد زیر مشاهده میکنید:
import { from} from 'rxjs/observable/from';
import { map, scan, filter } from 'rxjs/operators';
const source$ = range(1,10);
const sumOfSquaredOddNumbers$ = source$.pipe(
filter(n => n % 2 !== 0),
map(n => n * n),
scan((acc,s) => acc + s, 0)
);
sumOfSquaredOddNumbers$.subscribe(v => console.log(v));
/*** Output ****/
1
10
35
84
165
این مثال، جمع به توان 2 اعداد را در یک بازهی مشخص، محاسبه میکند. برای این منظور ابتدا یک منبع Observable توسط متد range ایجاد شدهاست.
در اینجا روش تعریف Observableها نیز تغییر کردهاست و از متد of جهت کار با تعدادی ورودی مشخص و یا متد range برای کار با بازهای از اعداد، استفاده میشود:
import { of } from 'rxjs/observable/of';
import { from } from 'rxjs/observable/from';
import { range } from 'rxjs/observable/range';
const source$ = of(1,2,3);
const rangeSource$ = range(0,5);
سپس توسط متد pipe، ترکیبی از متدهای RxJS را مشاهده میکند که بر روی منبع Observable اصلی کار میکنند.
متد filter، اعداد فرد بازه را انتخاب میکند. متد map این اعداد انتخابی را به توان 2 میرساند و سپس متد scan آنها را با هم جمع میزند و نتیجه توسط متد pipe به صورت یک Observable دیگر بازگشت داده میشود که میتوان مشترک آن شد و برای مثال خروجی فوق را در console درج کرد.
تغییر نام عملگرهای قبلی RxJS
تا اینجا دریافتیم که هدف اصلی pipeable/lettable operators، عدم معرفی آنها به صورت یک وصلهی جدید جدانشدنی از Observable.prototype، به صورت توابع خالص است. اکنون که این عملگرها، تبدیل به متدهای خالص و متکی به خود شدهاند، نباید با متدهای اصلی جاوا اسکریپت تداخل نام پیدا کنند؛ به همین جهت برای ارتقاء کدهای قدیمی خود، به این تغییر نامها نیاز خواهید داشت: متد do به tap تغییر نام یافتهاست. متد switch شدهاست switchAll. بجای catch اینبار catchError داریم و finally شدهاست finalize.
مثالی از ارتقاء کدهای قدیمی به روش جدید RxJS 5.5
اگر مثال روش قدیمی مبتنی بر وصله کردن Observable.prototype، به صورت زیر باشد:
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/filter';
names = allUserData.
map(user => user.name).
filter(name => name);
معادل جدید آن به این صورت تغییر میکند:
import { Observable } from 'rxjs/Observable';
import { map, filter } from 'rxjs/operators';
names = allUserData.pipe(
map(user => user.name),
filter(name => name),
);
زمانیکه تعریف Observable از مسیر rxjs/Observable درخواست میشود، به همراه عملگر وصله شدهی pipe نیز هست. به همین جهت نیازی به تعریف مجدد آن نیست. پس از آن متدهای map و filter، به داخل pipe منتقل میشوند. در این بین نیاز است تغییر نام متدها را که پیشتر نیز ذکر شد، مدنظر داشته باشید.
به عنوان یک مثال تکمیلی، کدهای سری «
احراز هویت و اعتبارسنجی کاربران در برنامههای Angular» جهت استفادهی از pipeable/lettable operators به روز رسانی شدهاند. لیست تغییرات آنها را
در اینجا میتوانید مشاهده کنید.