| وجه المقارنة المعمارية | الإدارة اليدوية للاشتراكات (Manual Subscriptions) | استخدام Async Pipe المعماري |
|---|---|---|
| إدارة الذاكرة وتسريب البيانات | تتطلب كتابة دوال `unsubscribe()` صريحة داخل دورة الحياة `ngOnDestroy` | تتم إدارة دورة حياة الاشتراك واستابه/إلغاؤه تلقائياً وبشكل كامل دون تدخل البرمجة اليدوية |
| طريقة كتابة القوالب وتحديث الحالة | تتطلب تخزين البيانات في متغيرات داخل صنف المكون وتحديثها عبر دوال `next()` | التعامل المباشر مع الـ Observable أو الـ Promise داخل القالب بكل مرونة |
| التوافق مع أحدث معايير الأداء والـ Signals | تتطلب تعقيداً إضافياً في إدارة الحالة والتزامن مع واجهة المستخدم | مدمجة بسلاسة وتتكامل بكفاءة مع تدفقات البيانات غير المتزامنة وأحدث أنظمة التحقق من الأداء |
في تطبيقات الويب الحديثة والمبنية بأحدث معايير Angular 22.1، تشكل البيانات القادمة من الخوادم عبر طلبات الشبكة (HTTP Requests) أو التدفقات المستمرة (Observables) العمود الفقري لتشغيل التطبيق. إدارة هذه البيانات يدوياً عبر الاشتراك (Subscription) في ملفات المكون ثم إلغاء الاشتراك لمنع تسريب الذاكرة (Memory Leaks) كان يمثل عبئاً هندسياً كبيراً. يأتي Async Pipe ليحل هذه المعضلة معمارياً، حيث يتولى إدارة الاشتراكات تلقائياً، وتحديث القالب لحظياً عند وصول البيانات، وإلغاء الاشتراك بمجرد تدمير المكون.
عندما تضع رمز الأنبوب async بجانب تدفق بيانات مثل Observable أو Promise في القالب، يقوم أنجولر تلقائياً بإنشاء اشتراك لاستقبال القيمة الجديدة، وحالما يختفي المكون من واجهة المستخدم، يقوم الأنبوب بإلغاء الاشتراك فواقاً لحماية الذاكرة.
يسهل هذا الأنبوب عرض البيانات المتجددة فور صدورها من الخادم دون الحاجة لكتابة أكواد مكررة لإدارة الحالة داخل صنف المكون (TypeScript Class)، مما يحافظ على نظافة المعمارية البرمجية (Clean Architecture).
| 1 | import { Component } from '@angular/core'; |
| 2 | import { CommonModule } from '@angular/common'; |
| 3 | import { Observable, interval } from 'rxjs'; |
| 4 | import { map, take } from 'rxjs/operators'; |
| 5 | |
| 6 | @Component({ |
| 7 | selector: 'app-async-pipe-demo', |
| 8 | standalone: true, |
| 9 | imports: [CommonModule], |
| 10 | template: ` |
| 11 | <div class="master-container"> |
| 12 | <h3>التعامل مع البيانات غير المتزامنة (Async Pipe)</h3> |
| 13 | <p>مراقبة تدفق البيانات المباشر وقراءة الـ Observables تلقائياً:</p> |
| 14 | |
| 15 | <div class="data-card"> |
| 16 | <p><strong>حالة المؤقت الزمني المتجدد:</strong> {{ timerStream$ | async }} ثانية</p> |
| 17 | </div> |
| 18 | |
| 19 | <div class="data-card"> |
| 20 | <p><strong>بيانات المستخدم القادمة من الوعد (Promise):</strong></p> |
| 21 | <p>{{ userInfoPromise | async }}</p> |
| 22 | </div> |
| 23 | </div> |
| 24 | `, |
| 25 | styles: [` |
| 26 | .master-container { background: #090d16; color: #fff; padding: 24px; border-radius: 12px; } |
| 27 | .data-card { background: #1e293b; color: #38bdf8; padding: 16px; border-radius: 8px; margin: 12px 0; border: 1px solid #334155; font-weight: bold; } |
| 28 | .data-card p { margin: 8px 0; color: #e2e8f0; } |
| 29 | `] |
| 30 | }) |
| 31 | export class AsyncPipeDemoComponent { |
| 32 | // مؤقت زمني يحاكي تدفق بيانات حقيقي |
| 33 | timerStream$: Observable<number> = interval(1000).pipe( |
| 34 | map(val => val + 1) |
| 35 | ); |
| 36 | |
| 37 | // وعد يحاكي جلب بيانات المستخدم من الخادم |
| 38 | userInfoPromise: Promise<string> = new Promise((resolve) => { |
| 39 | setTimeout(() => { |
| 40 | resolve('تم بنجاح جلب ملف المستخدم المعماري برتبة Senior Architect من الخادم.'); |
| 41 | }, 2000); |
| 42 | }); |
| 43 | } |
| 1 | import { Component } from '@angular/core'; |
| 2 | import { CommonModule } from '@angular/common'; |
| 3 | import { Observable, of } from 'rxjs'; |
| 4 | import { delay } from 'rxjs/operators'; |
| 5 | |
| 6 | interface ProjectTask { |
| 7 | id: number; |
| 8 | title: string; |
| 9 | completed: boolean; |
| 10 | } |
| 11 | |
| 12 | @Component({ |
| 13 | selector: 'app-async-list-demo', |
| 14 | standalone: true, |
| 15 | imports: [CommonModule], |
| 16 | template: ` |
| 17 | <div class="master-container"> |
| 18 | <h3>عرض القوائم غير المتزامنة بدمج Async مع كتل التوجيه الحديثة</h3> |
| 19 | |
| 20 | @if (tasksStream$ | async; as tasks) { |
| 21 | <ul class="task-list"> |
| 22 | @for (task of tasks; track task.id) { |
| 23 | <li class="task-item"> |
| 24 | <span>{{ task.title }}</span> |
| 25 | <span [style.color]="task.completed ? '#34d399' : '#f87171'"> |
| 26 | {{ task.completed ? 'مكتملة' : 'قيد التنفيذ' }} |
| 27 | </span> |
| 28 | </li> |
| 29 | } |
| 30 | </ul> |
| 31 | } @else { |
| 32 | <p class="loading-text">جاري جلب مهام المشروع المعماري...</p> |
| 33 | } |
| 34 | </div> |
| 35 | `, |
| 36 | styles: [` |
| 37 | .master-container { background: #090d16; color: #fff; padding: 24px; border-radius: 12px; margin-top: 16px; } |
| 38 | .task-list { list-style: none; padding: 0; margin: 0; } |
| 39 | .task-item { background: #1e293b; padding: 12px 16px; border-radius: 8px; margin: 8px 0; display: flex; justify-content: space-between; border: 1px solid #334155; } |
| 40 | .loading-text { color: #f59e0b; font-weight: bold; } |
| 41 | `] |
| 42 | }) |
| 43 | export class AsyncListDemoComponent { |
| 44 | // محاكاة استجابة خادم تحتوي على قائمة مهام بعد تأخير زمني |
| 45 | tasksStream$: Observable<ProjectTask[]> = of([ |
| 46 | { id: 1, title: 'إعداد بنية المشروع الهندسية', completed: true }, |
| 47 | { id: 2, title: 'تطوير الأنابيب المخصصة', completed: false }, |
| 48 | { id: 3, title: 'تحبار اختبارات الأداء المتقدمة', completed: false } |
| 49 | ]).pipe(delay(1500)); |
| 50 | } |
| 1 | import { Component } from '@angular/core'; |
| 2 | import { CommonModule } from '@angular/common'; |
| 3 | import { Observable, throwError, of } from 'rxjs'; |
| 4 | import { catchError, delay } from 'rxjs/operators'; |
| 5 | |
| 6 | @Component({ |
| 7 | selector: 'app-async-error-demo', |
| 8 | standalone: true, |
| 9 | imports: [CommonModule], |
| 10 | template: ` |
| 11 | <div class="master-container"> |
| 12 | <h3>التعامل الآمن مع تدفقات البيانات المعرضة للأخطاء</h3> |
| 13 | |
| 14 | <div class="data-card"> |
| 15 | @if (secureData$ | async; track $index; as data) { |
| 16 | <p><strong>البيانات المستلمة بأمان:</strong> {{ data }}</p> |
| 17 | } @placeholder { |
| 18 | <p>جاري فحص الاتصال بالخادم...</p> |
| 19 | } |
| 20 | </div> |
| 21 | </div> |
| 22 | `, |
| 23 | styles: [` |
| 24 | .master-container { background: #090d16; color: #fff; padding: 24px; border-radius: 12px; margin-top: 16px; } |
| 25 | .data-card { background: #1e293b; color: #38bdf8; padding: 16px; border-radius: 8px; margin: 12px 0; border: 1px solid #334155; font-weight: bold; } |
| 26 | `] |
| 27 | }) |
| 28 | export class AsyncErrorDemoComponent { |
| 29 | secureData$: Observable<string> = of('تم التحقق من الصلاحيات الهندسية بنجاح').pipe( |
| 30 | delay(1000), |
| 31 | catchError(err => of('حدث خطأ أثناء جلب البيانات، وتم التعامل معه بنجاح.')) |
| 32 | ); |
| 33 | } |