| العنصر الداخلي (`Internal Component`) | دوره في معمارية التدفق اليدوي | طريقة الاستخدام البرمجية الصحيحة |
|---|---|---|
| مُستقبل البيانات (`Subscriber`) | نقطة الاتصال التي تمرر البيانات أو الأخطاء أو إعلانات الانتهاء للمستهلك | استخدام `subscriber.next(val)` أو `subscriber.complete()` |
| دالة التنظيف (`Teardown Logic`) | إرجاع دالة مسؤولة عن إلغاء المؤقتات أو الاتصالات فور إلغاء الاشتراك | كتابة `return () => { clearInterval(id); }` داخل الـ Producer |
| التحكم الكسول (`Lazy Execution Control`) | ضمان عدم تنفيذ كود الإنشاء إلا عند تفعيل عملية الاشتراك (`subscribe`) | بدء تنفيذ العمليات الثقيلة فقط عند الحاجة الفعلية للمستهلك |
لا تحتاج دائماً إلى بناء Observable معقد من الصفر. توفر مكتبة RxJS دالات إنشاء ثابتة (Creation Functions) مثل of و from، والتي تتيح لك تحويل المصفوفات، الكائنات الثابتة، أو الوعود (Promises) إلى تدفقات تفاعلية جاهزة للاستخدام في ثوانٍ معدودة، مما يرفع من إنتاجية المطور ونظافة الكود.
عندما تتعامل مع بيانات محلية أو قوائم ثابتة تريد إخضاعها لمعالجة عبر مشغلات RxJS، فإن استخدام of و from يختصر الكثير من الأكواد مقارنة ببناء التدفقات اليدوية الطويلة.
تستطيع دالة from استيعاب أي Promise قادم من الخادم وتحويله بسلاسة إلى Observable، مما يتيح لك دمجه مباشرة داخل الـ pipe وتطبيق عمليات المعالجة والأخطاء بكل مهارة.
| 1 | import { Component, OnInit } from '@angular/core'; |
| 2 | import { CommonModule } from '@angular/common'; |
| 3 | import { of, Observable } from 'rxjs'; |
| 4 | |
| 5 | @Component({ |
| 6 | selector: 'app-of-operator-demo', |
| 7 | standalone: true, |
| 8 | imports: [CommonModule], |
| 9 | template: ` |
| 10 | <div class="demo-card"> |
| 11 | <h3>استخدام دالة الإنشاء of لتحويل البيانات الثابتة</h3> |
| 12 | <p><strong>النتيجة المعروضة من التدفق الثابت:</strong> {{ streamResult }}</p> |
| 13 | </div> |
| 14 | `, |
| 15 | styles: [` |
| 16 | .demo-card { background: #090d16; color: #fff; padding: 20px; border-radius: 10px; border: 1px solid #1e293b; margin-bottom: 16px; } |
| 17 | .demo-card p { color: #38bdf8; font-weight: bold; } |
| 18 | `] |
| 19 | }) |
| 20 | export class OfOperatorDemoComponent implements OnInit { |
| 21 | streamResult: string = ''; |
| 22 | myStaticObservable$: Observable<string> = of('أنجولر 22.1', 'معمارية متقدمة', 'تدفقات تفاعلية'); |
| 23 | |
| 24 | ngOnInit(): void { |
| 25 | this.myStaticObservable$.subscribe(value => { |
| 26 | this.streamResult = value; |
| 27 | console.log('قيمة صادرة من of:', value); |
| 28 | }); |
| 29 | } |
| 30 | } |
⚠️ تحذير
تذكر أن of و from تغلق التدفق تلقائياً (Complete) فور انتهاء إرسال القيم! هذا يعني أنك لا تحتاج إلى إنشاء دالّة تدمير يدوية لإلغاء الاشتراك لهذه التدفقات الثابتة، بخلاف التدفقات المستمرة مثل interval أو fromEvent.
| 1 | import { Component, OnInit } from '@angular/core'; |
| 2 | import { CommonModule } from '@angular/common'; |
| 3 | import { from, Observable } from 'rxjs'; |
| 4 | |
| 5 | @Component({ |
| 6 | selector: 'app-from-array-demo', |
| 7 | standalone: true, |
| 8 | imports: [CommonModule], |
| 9 | template: ` |
| 10 | <div class="demo-card"> |
| 11 | <h3>استخدام دالة الإنشاء from لفك المصفوفات</h3> |
| 12 | <ul> |
| 13 | <li *ngFor="let item of processedItems">{{ item }}</li> |
| 14 | </ul> |
| 15 | </div> |
| 16 | `, |
| 17 | styles: [` |
| 18 | .demo-card { background: #090d16; color: #fff; padding: 20px; border-radius: 10px; border: 1px solid #1e293b; margin-bottom: 16px; } |
| 19 | ul { color: #94a3b8; padding-right: 20px; } |
| 20 | li { color: #10b981; margin: 4px 0; } |
| 21 | `] |
| 22 | }) |
| 23 | export class FromArrayDemoComponent implements OnInit { |
| 24 | processedItems: string[] = []; |
| 25 | frameworksList = ['Angular', 'RxJS', 'TypeScript', 'NgRx Signals']; |
| 26 | myArrayObservable$: Observable<string> = from(this.frameworksList); |
| 27 | |
| 28 | ngOnInit(): void { |
| 29 | this.myArrayObservable$.subscribe({ |
| 30 | next: (val) => { |
| 31 | this.processedItems.push(val); |
| 32 | console.log('عصر عنصر فردي من المصفوفة عبر from:', val); |
| 33 | }, |
| 34 | complete: () => console.log('تم اكتمال تدفق المصفوفة بنجاح.') |
| 35 | }); |
| 36 | } |
| 37 | } |
| 1 | import { Component, OnInit } from '@angular/core'; |
| 2 | import { CommonModule } from '@angular/common'; |
| 3 | import { from, Observable } from 'rxjs'; |
| 4 | |
| 5 | @Component({ |
| 6 | selector: 'app-from-promise-demo', |
| 7 | standalone: true, |
| 8 | imports: [CommonModule], |
| 9 | template: ` |
| 10 | <div class="demo-card"> |
| 11 | <h3>تحويل الوعود غير المتزامنة (Promises) إلى تدفقات</h3> |
| 12 | <p><strong>بيانات الوعد المُستقبلة:</strong> {{ promiseData || 'جاري جلب البيانات...' }}</p> |
| 13 | </div> |
| 14 | `, |
| 15 | styles: [` |
| 16 | .demo-card { background: #090d16; color: #fff; padding: 20px; border-radius: 10px; border: 1px solid #1e293b; } |
| 17 | .demo-card p { color: #38bdf8; } |
| 18 | `] |
| 19 | }) |
| 20 | export class FromPromiseDemoComponent implements OnInit { |
| 21 | promiseData: string = ''; |
| 22 | |
| 23 | ngOnInit(): void { |
| 24 | // محاكاة طلب خادم عبر Promise |
| 25 | const mockServerPromise = new Promise<string>((resolve) => { |
| 26 | setTimeout(() => { |
| 27 | resolve('تم استلام البيانات بنجاح من الخادم عبر الوعد المحول!'); |
| 28 | }, 1500); |
| 29 | }); |
| 30 | |
| 31 | // تحويل الوعود إلى Observable باستخدام from |
| 32 | const promiseObservable$: Observable<string> = from(mockServerPromise); |
| 33 | |
| 34 | promiseObservable$.subscribe({ |
| 35 | next: (data) => { |
| 36 | this.promiseData = data; |
| 37 | console.log('نتيجة الوعد المحول:', data); |
| 38 | } |
| 39 | }); |
| 40 | } |
| 41 | } |