Observables In ANGULAR 2+-

 Observables In ANGULAR 2+

جدول المصطلحات:

المصطلح

التعريف

Observable

تدفق بيانات غير متزامن يمكن الاشتراك فيه لاستقبال قيم متعددة بمرور الوقت. 



Subscription

كائن يمثل عملية الاشتراك في Observable، ويستخدم لإلغاء الاشتراك عند الحاجة.


Promise

كائن يمثل عملية غير متزامنة تنتج قيمة واحدة فقط (إما نجاح أو فشل). 


Subject

نوع خاص من Observable يسمح بإرسال القيم إلى العديد من المشتركين.


مقدمة

المراقبات (Observables) في Angular هي حجر الأساس للتعامل مع البيانات غير المتزامنة والتفاعلات في التطبيقات الحديثة. تعتمد Angular بشكل كامل على مكتبة RxJS (Reactive Extensions for JavaScript) لتنفيذ هذا النمط التفاعلي.

ما هي المراقبات (Observables)؟

المراقبات هي تدفقات بيانات غير متزامنة تسمح بالاشتراك فيها لاستقبال قيم متعددة بمرور الوقت. تختلف عن الوعود (Promises) في قدرتها على إرجاع قيم متعددة بدلاً من قيمة واحدة.



الميزة

Observable

Promise

عدد القيم

متعددة (تدفق مستمر)

قيمة واحدة فقط

الإلغاء

يدعم (unsubscribe())

لا يدعم

التنفيذ

كسول (Lazy) - يبدأ عند الاشتراك

متحمس (Eager) - يبدأ عند الإنشاء

المشغلات

يدعم (Operators) للتحويل

لا يدعم



إنشاء Observable بسيط

typescript

import { Observable } from 'rxjs';


// إنشاء Observable يدوياً

const customObservable = new Observable(subscriber => {

  let count = 0;

  const interval = setInterval(() => {

    subscriber.next(count); // إرسال قيمة

    count++;

    

    if (count === 3) {

      subscriber.error('حدث خطأ عند الرقم 3'); // إرسال خطأ

    }

    

    if (count === 5) {

      subscriber.complete(); // إعلام بالاكتمال

      clearInterval(interval);

    }

  }, 1000);

});


// الاشتراك في Observable

const subscription = customObservable.subscribe({

  next: (value) => console.log('القيمة المستلمة:', value),

  error: (err) => console.error('حدث خطأ:', err),

  complete: () => console.log('اكتمل تدفق البيانات!')

});


// إلغاء الاشتراك (مهم لمنع تسرب الذاكرة)

setTimeout(() => {

  subscription.unsubscribe();

  console.log('تم إلغاء الاشتراك');

}, 7000);

أنواع الإشعارات في Observable

المراقب يرسل ثلاثة أنواع من الإشعارات:

1. Next (قادم)

  • الوظيفة: إرسال قيمة جديدة

  • التكرار: يمكن استدعاؤه صفر، مرة، أو عدة مرات

  • مثال: subscriber.next('مرحباً')

2. Error (خطأ)

  • الوظيفة: إرسال خطأ يوقف التنفيذ

  • التأثير: يؤدي إلى إنهاء الاشتراك تلقائياً

  • مثال: subscriber.error(new Error('حدث خطأ'))

3. Complete (مكتمل)

  • الوظيفة: إشعار بانتهاء تدفق البيانات

  • التأثير: لا يمكن إرسال قيم بعدها

  • مثال: subscriber.complete()


ملاحظة مهمة: بعد إرسال error أو complete، لا يمكن إرسال المزيد من القيم.

أمثلة عملية من المقال الأصلي

مثال 1: استخدام interval المدمج

typescript

import { Component, OnInit, OnDestroy } from '@angular/core';

import { Subscription, interval } from 'rxjs';


@Component({

  selector: 'app-timer',

  template: `<p>العداد: {{counter}}</p>`

})

export class TimerComponent implements OnInit, OnDestroy {

  counter = 0;

  private subscription: Subscription;


  ngOnInit() {

    this.subscription = interval(1000).subscribe({

      next: (value) => {

        this.counter = value;

        console.log('القيمة:', value);

      }

    });

  }


  ngOnDestroy() {

    // إلغاء الاشتراك لمنع تسرب الذاكرة

    this.subscription.unsubscribe();

  }

}


مثال 2: بناء Observable مخصص

typescript

// بناء Observable يدوي كما في الصورة الأصلية

const customIntervalObservable = new Observable(subscriber => {

  let count = 0;

  const intervalId = setInterval(() => {

    subscriber.next(count);

    count++;

    

    if (count > 10) {

      subscriber.complete();

      clearInterval(intervalId);

    }

  }, 1000);

  

  // دالة التنظيف عند إلغاء الاشتراك

  return () => {

    console.log('تم تنظيف الموارد');

    clearInterval(intervalId);

  };

});

استخدام Observable مع Angular Services

مثال مع HttpClient:

typescript

import { HttpClient } from '@angular/common/http';

import { Component, OnInit } from '@angular/core';

import { Observable } from 'rxjs';


interface User {

  id: number;

  name: string;

  email: string;

}


@Component({

  selector: 'app-user-list',

  template: `

    <ul>

      <li *ngFor="let user of users$ | async">

        {{user.name}} - {{user.email}}

      </li>

    </ul>

  `

})

export class UserListComponent implements OnInit {

  users$: Observable<User[]>;


  constructor(private http: HttpClient) {}


  ngOnInit() {

    // HttpClient يعيد Observable

    this.users$ = this.http.get<User[]>('https://api.example.com/users');

    

    // الاشتراك التقليدي

    this.http.get<User[]>('https://api.example.com/users').subscribe({

      next: (users) => console.log('المستخدمون:', users),

      error: (err) => console.error('خطأ:', err),

      complete: () => console.log('اكتمل جلب البيانات')

    });

  }

}



الموضوعات (Subjects) - نوع خاص من Observables

typescript

import { Subject } from 'rxjs';


// إنشاء Subject

const messageBus = new Subject<string>();


// اشتراك متعدد

messageBus.subscribe(msg => console.log('المستخدم 1:', msg));

messageBus.subscribe(msg => console.log('المستخدم 2:', msg));


// إرسال قيمة (ستصل للمشتركين جميعاً)

messageBus.next('مرحباً بالجميع!');

messageBus.next('كيف الحال؟');


// إغلاق Subject

messageBus.complete();


// Subject خاص يرسل آخر قيمة للمشتركين الجدد

import { BehaviorSubject } from 'rxjs';


const userStatus = new BehaviorSubject<string>('غير متصل');

userStatus.subscribe(status => console.log('الحالة:', status));


userStatus.next('متصل'); // سيتم استلامها من المشترك الحالي

userStatus.subscribe(status => console.log('مشترك جديد:', status)); // سيستقبل 'متصل' فوراً



المشغلات (Operators) - تحويل وتصفية البيانات


typescript

import { of } from 'rxjs';

import { map, filter, tap, take } from 'rxjs/operators';


const numbers$ = of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);


numbers$.pipe(

  filter(num => num % 2 === 0),       // أرقام زوجية فقط

  map(num => num * 10),               // ضرب في 10

  tap(num => console.log('القيمة:', num)), // تنفيذ تأثير جانبي

  take(3)                             // أخذ أول 3 قيم فقط

).subscribe(result => {

  console.log('النتيجة النهائية:', result);

});


// الناتج:

// القيمة: 20

// النتيجة النهائية: 20

// القيمة: 40

// النتيجة النهائية: 40

// القيمة: 60

// النتيجة النهائية: 60


أفضل الممارسات في Angular

1. استخدام Async Pipe في القوالب

typescript

@Component({

  selector: 'app-example',

  template: `

    <div *ngIf="user$ | async as user">

      <h2>{{user.name}}</h2>

      <p>{{user.email}}</p>

    </div>

    

    <ul>

      <li *ngFor="let item of items$ | async">

        {{item.name}}

      </li>

    </ul>

  `

})

export class ExampleComponent {

  user$ = this.http.get<User>('/api/user/1');

  items$ = this.http.get<Item[]>('/api/items');

  

  constructor(private http: HttpClient) {}

}


2. إلغاء الاشتراك تلقائياً

typescript

import { Component, OnDestroy } from '@angular/core';

import { Subject } from 'rxjs';

import { takeUntil } from 'rxjs/operators';


@Component({

  selector: 'app-safe',

  template: `...`

})

export class SafeComponent implements OnDestroy {

  private destroy$ = new Subject<void>();

  

  constructor() {

    interval(1000)

      .pipe(takeUntil(this.destroy$))

      .subscribe(value => console.log(value));

  }

  

  ngOnDestroy() {

    this.destroy$.next();

    this.destroy$.complete();

  }

}



3. معالجة الأخطاء بشكل صحيح

typescript

import { Component, OnDestroy } from '@angular/core';

import { Subject } from 'rxjs';

import { takeUntil } from 'rxjs/operators';


@Component({

  selector: 'app-safe',

  template: `...`

})

export class SafeComponent implements OnDestroy {

  private destroy$ = new Subject<void>();

  

  constructor() {

    interval(1000)

      .pipe(takeUntil(this.destroy$))

      .subscribe(value => console.log(value));

  }

  

  ngOnDestroy() {

    this.destroy$.next();

    this.destroy$.complete();

  }

}


مثال متكامل من الحياة الواقعية


typescript

import { Component, OnInit, OnDestroy } from '@angular/core';

import { HttpClient } from '@angular/common/http';

import { Subject, interval, merge } from 'rxjs';

import { 

  takeUntil, 

  switchMap, 

  catchError, 

  startWith,

  map 

} from 'rxjs/operators';


interface StockPrice {

  symbol: string;

  price: number;

  timestamp: Date;

}


@Component({

  selector: 'app-stock-tracker',

  template: `

    <h2>تتبع أسعار الأسهم</h2>

    <div *ngFor="let stock of stocks">

      <p>{{stock.symbol}}: {{stock.price | currency}}</p>

      <small>{{stock.timestamp | date:'medium'}}</small>

    </div>

    <button (click)="stopTracking()">إيقاف التتبع</button>

  `

})

export class StockTrackerComponent implements OnInit, OnDestroy {

  stocks: StockPrice[] = [];

  private destroy$ = new Subject<void>();

  

  constructor(private http: HttpClient) {}

  

  ngOnInit() {

    // تحديث الأسهم كل 5 ثوانٍ

    interval(5000).pipe(

      startWith(0), // البدء فوراً

      switchMap(() => this.fetchStockPrices()),

      takeUntil(this.destroy$)

    ).subscribe({

      next: (prices) => this.stocks = prices,

      error: (err) => console.error('خطأ في تتبع الأسهم:', err)

    });

  }

  

  private fetchStockPrices() {

    return this.http.get<StockPrice[]>('/api/stocks').pipe(

      catchError(error => {

        console.error('فشل جلب البيانات:', error);

        return of([]); // إرجاع مصفوفة فارغة عند الخطأ

      })

    );

  }

  

  stopTracking() {

    this.destroy$.next();

  }

  

  ngOnDestroy() {

    this.destroy$.next();

    this.destroy$.complete();

  }

}

المشاكل الشائعة والحلول:

المشكلة

السبب

الحل

تسرب الذاكرة

نسيان إلغاء الاشتراك

استخدام Async Pipe أو takeUntil

الاشتراك المتعدد

استدعاء subscribe عدة مرات

استخدام share() أو shareReplay()

الأخطاء غير المعالجة

عدم استخدام catchError

إضافة معالج أخطاء في pipe

تحديثات غير ضرورية

كثرة القيم المرسلة

استخدام debounceTime أو throttleTime

المصادر

  1. الدليل الرسمي لـ Angular عن Observables

  2. وثائق RxJS الرسمية

  3. مكتبة RxJS في Angular

  4. أنواع Subjects في RxJS

الخاتمة

المراقبات (Observables) هي أداة قوية في Angular تمكنك من التعامل مع البيانات غير المتزامنة والأحداث بشكل فعال. إتقانها يتطلب فهم:

  1. الإنشاء و الاشتراك الأساسي

  2. المشغلات (Operators) للتحويل والتصفية

  3. الموضوعات (Subjects) للتواصل بين المكونات

  4. أفضل الممارسات لمنع المشاكل الشائعة

باستخدام هذه المفاهيم، يمكنك بناء تطبيقات Angular أكثر كفاءة وسهولة في الصيانة.


Observables In ANGULAR 2+-  Observables In ANGULAR 2+- بواسطة Remocolla Academy في مارس 25, 2026 تقييم: 5

ليست هناك تعليقات:

يتم التشغيل بواسطة Blogger.