| الأداة أو المشغل (`Operator`) | دوره المعماري الأساسي في التدفق | التأثير المباشر عند وقوع الاستثناء |
|---|---|---|
| `catchError` | اعتراض الخطأ القادم من التدفق ومنع انهياره | إرجاع تدفق بديل (Fallback Stream) أو إصدار قيمة آمنة افتراضية للمستخدم |
| `retry` | محاولة إعادة الاشتراك التلقائي في التدفق لعدد محدد من المرات فور فشله | التغلب على الأعطال المؤقتة في الشبكة دون تدخل يدوي من المستخدم |
| `retryWhen` | تخصيص استراتيجيات معقدة لإعادة المحاولة (مثل تأخير زمني تدريجي) | التحكم الدقيق في توقيتات محاولات الاتصال بالخادم عند السقوط المتكرر |
تُعد موثوقية التطبيق واستمراريته في مواجهة استثناءات الشبكة أو أخطاء الخادم أمراً حتمياً. الاعتماد على معالجة بدائية للأخطاء قد يؤدي إلى انهيار واجهة المستخدم بالكامل. توفر مكتبة RxJS أدوات هندسية متقدمة مثل catchError و retry لإدارة الأخطاء بأمان وتقديم بدائل مرنة تضمن بقاء النظام مستقراً وسلس الاستجابة.
عندما يحدث خطأ شبكي أو استثناء برمجي، فإن التدفق ينغلق نهائياً. يتيح لك catchError التقاط هذا الاستثناء وتحويله إلى قيمة بديلة (مثل مصفوفة فارغة أو رسالة خطأ واضحة) بدلاً من ترك التطبيق معطلاً.
في طلبات الخوادم غير المتوقعة أو بطء الاتصال المؤقت، يتيح لك retry(n) إعادة محاولة جلب البيانات تلقائياً n مرات قبل إعلان الفشل النهائي وإظهار خطأ للمستخدم.
| 1 | import { Component, OnInit } from '@angular/core'; |
| 2 | import { CommonModule } from '@angular/common'; |
| 3 | import { Observable, throwError, of, Subscription } from 'rxjs'; |
| 4 | import { catchError, retry, tap } from 'rxjs/operators'; |
| 5 | |
| 6 | @Component({ |
| 7 | selector: 'app-network-error-handling', |
| 8 | standalone: true, |
| 9 | imports: [CommonModule], |
| 10 | template: ` |
| 11 | <div class="error-demo-card"> |
| 12 | <h3>إدارة أخطاء الشبكة وإعادة المحاولة التلقائية</h3> |
| 13 | <p><strong>حالة البيانات المُستلمة:</strong> {{ apiResponseData }}</p> |
| 14 | <p class="error-msg" *ngIf="errorMessage"><strong>رسالة الخطأ المعالجة:</strong> {{ errorMessage }}</p> |
| 15 | </div> |
| 16 | `, |
| 17 | styles: [` |
| 18 | .error-demo-card { background: #090d16; color: #fff; padding: 24px; border-radius: 12px; border: 1px solid #1e293b; margin-bottom: 16px; } |
| 19 | p { color: #94a3b8; margin: 8px 0; } |
| 20 | strong { color: #38bdf8; } |
| 21 | .error-msg { color: #f87171; } |
| 22 | `] |
| 23 | }) |
| 24 | export class NetworkErrorHandlingComponent implements OnInit { |
| 25 | apiResponseData: string = ''; |
| 26 | errorMessage: string = ''; |
| 27 | private sub!: Subscription; |
| 28 | |
| 29 | ngOnInit(): void { |
| 30 | let attemptCount = 0; |
| 31 | |
| 32 | // محاكاة تدفق بيانات شبكي يفشل أول مرتين ثم ينجح أو يعود بقيمة افتراضية |
| 33 | const unstableApiCall$ = new Observable<string>((subscriber) => { |
| 34 | attemptCount++; |
| 35 | console.log(`محاولة الاتصال بالخادم رقم: ${attemptCount}`); |
| 36 | |
| 37 | if (attemptCount < 3) { |
| 38 | subscriber.error('فشل الاتصال بالخادم (Network Timeout)'); |
| 39 | } else { |
| 40 | subscriber.next('بيانات الخادم الحقيقية بنجاح!'); |
| 41 | subscriber.complete(); |
| 42 | } |
| 43 | }); |
| 44 | |
| 45 | this.sub = unstableApiCall$.pipe( |
| 46 | tap(val => console.log('قيمة ناجحة مارّة:', val)), |
| 47 | retry(2), // إعادة المحاولة مرتين تلقائياً عند حدوث خطأ |
| 48 | catchError((error) => { |
| 49 | console.warn('تم التقاط الخطأ نهائياً بعد استنفاد محاولات الـ retry:', error); |
| 50 | this.errorMessage = error; |
| 51 | // إرجاع تدفق بديل آمن (Fallback) لكي لا ينهار المكون |
| 52 | return of('تم تحميل البيانات البديلة المخزنة محلياً بنجاح.'); |
| 53 | }) |
| 54 | ).subscribe({ |
| 55 | next: (result) => { |
| 56 | this.apiResponseData = result; |
| 57 | }, |
| 58 | complete: () => console.log('انتهى تدفق معالجة الشبكة بأمان.') |
| 59 | }); |
| 60 | } |
| 61 | |
| 62 | ngOnDestroy(): void { |
| 63 | if (this.sub) { |
| 64 | this.sub.unsubscribe(); |
| 65 | } |
| 66 | } |
| 67 | } |
| 1 | import { Component, OnInit } from '@angular/core'; |
| 2 | import { CommonModule } from '@angular/common'; |
| 3 | import { throwError, of, Subscription } from 'rxjs'; |
| 4 | import { catchError, map } from 'rxjs/operators'; |
| 5 | |
| 6 | @Component({ |
| 7 | selector: 'app-user-dashboard-fallback', |
| 8 | standalone: true, |
| 9 | imports: [CommonModule], |
| 10 | template: ` |
| 11 | <div class="error-demo-card"> |
| 12 | <h3>لوحة التحكم: التعامل مع حالة البيانات الفارغة أو المعطلة</h3> |
| 13 | <ul> |
| 14 | <li *ngFor="let item of dashboardItems">{{ item }}</li> |
| 15 | </ul> |
| 16 | <p class="fallback-note" *ngIf="isFallbackActive">ملاحظة: يتم عرض بيانات الطوارئ نظراً لتعطل الخدمة الرئيسية.</p> |
| 17 | </div> |
| 18 | `, |
| 19 | styles: [` |
| 20 | .error-demo-card { background: #090d16; color: #fff; padding: 24px; border-radius: 12px; border: 1px solid #1e293b; } |
| 21 | ul { color: #94a3b8; padding-right: 20px; } |
| 22 | li { color: #10b981; margin: 4px 0; } |
| 23 | .fallback-note { color: #facc15; font-size: 0.9rem; margin-top: 12px; } |
| 24 | `] |
| 25 | }) |
| 26 | export class UserDashboardFallbackComponent implements OnInit { |
| 27 | dashboardItems: string[] = []; |
| 28 | isFallbackActive: boolean = false; |
| 29 | private dashboardSub!: Subscription; |
| 30 | |
| 31 | } |