| طريقة الإدارة (`Management Approach`) | آلية التنفيذ الهندسي | مميزات الاستخدام في التطبيقات الكبيرة |
|---|---|---|
| الإلغاء اليدوي (`Manual Unsubscription`) | استدعاء `subscription.unsubscribe()` داخل دالة `ngOnDestroy` | تحكم كامل ولكنها تتطلب كتابة كود مكرر وعرضة للنسيان |
| نمط `takeUntil` التقليدي | استخدام Subject وهمي يتم تفعيل إغلاقه عند تدمير المكون | ربط إغلاق التدفق بدورة حياة المكون بشكل برمجي داخل الـ pipe |
| أنجولر الحديثة `takeUntilDestroyed` | استخدام الدالة المعمارية الجديدة بدون الحاجة لتعريف متغيرات تدمير يدوية | الخيار الأقوى والأكثر نظافة في أنجولر الحديثة للتنظيف التلقائي |
تُعتبر إدارة الذاكرة وحماية التطبيق من التسريبات (Memory Leaks) المعيار الحقيقي لمدى احترافية المطور. بقاء الاشتراكات النشطة (Active Subscriptions) بعد مغادرة المكون أو تدميره يؤدي إلى استنزاف موارد المتصفح ببطء. توفر أنجولر الحديثة أدوات جبارة مثل takeUntilDestroyed وأنماط الإلغاء اليدوي لضمان تنظيف الموارد بدقة متناهية.
عندما يشترك المكون في تدفق مستمر (مثل interval أو أحداث DOM أو خدمة عامة) وينسى المطور إلغاء الاشتراك، سيبقى المكون مخزناً في الذاكرة ولن يستطيع نظام Garbage Collection حذفه، مما يسبب بطء تدريجي في الأداء.
في النسخ الحديثة، يتيح لك ربط التدفق بـ takeUntilDestroyed() إلغاء الاشتراك تلقائياً وفوراً بمجرد تدمير المكون، مما يلغي تماماً الحاجة لكتابة كود ngOnDestroy المتكرر.
| 1 | import { Component, OnInit, OnDestroy } from '@angular/core'; |
| 2 | import { CommonModule } from '@angular/common'; |
| 3 | import { interval, Subscription } from 'rxjs'; |
| 4 | |
| 5 | @Component({ |
| 6 | selector: 'app-manual-unsubscribe-demo', |
| 7 | standalone: true, |
| 8 | imports: [CommonModule], |
| 9 | template: ` |
| 10 | <div class="memory-card"> |
| 11 | <h3>الإدارة اليدوية للاشتراكات عبر OnDestroy</h3> |
| 12 | <p><strong>قيمة العداد النشط:</strong> {{ currentCount }}</p> |
| 13 | </div> |
| 14 | `, |
| 15 | styles: [` |
| 16 | .memory-card { background: #090d16; color: #fff; padding: 24px; border-radius: 12px; border: 1px solid #1e293b; margin-bottom: 16px; } |
| 17 | p { color: #94a3b8; } |
| 18 | strong { color: #38bdf8; } |
| 19 | `] |
| 20 | }) |
| 21 | export class ManualUnsubscribeDemoComponent implements OnInit, OnDestroy { |
| 22 | currentCount: number = 0; |
| 23 | private countSubscription!: Subscription; |
| 24 | |
| 25 | ngOnInit(): void { |
| 26 | // إنشاء اشتراك في تدفق زمني مستمر |
| 27 | this.countSubscription = interval(1000).subscribe({ |
| 28 | next: (val) => { |
| 29 | this.currentCount = val; |
| 30 | console.log('قيمة العداد الحالية:', val); |
| 31 | } |
| 32 | }); |
| 33 | } |
| 34 | |
| 35 | ngOnDestroy(): void { |
| 36 | // التأكد من إلغاء الاشتراك يدوياً لمنع تسريب الذاكرة عند تدمير المكون |
| 37 | if (this.countSubscription) { |
| 38 | this.countSubscription.unsubscribe(); |
| 39 | console.log('تم إلغاء الاشتراك اليدوي بنجاح وتطهير الذاكرة.'); |
| 40 | } |
| 41 | } |
| 42 | } |
| 1 | import { Component, OnInit, DestroyRef, inject } from '@angular/core'; |
| 2 | import { CommonModule } from '@angular/common'; |
| 3 | import { interval } from 'rxjs'; |
| 4 | import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; |
| 5 | |
| 6 | @Component({ |
| 7 | selector: 'app-modern-take-until-destroyed', |
| 8 | standalone: true, |
| 9 | imports: [CommonModule], |
| 10 | template: ` |
| 11 | <div class="memory-card"> |
| 12 | <h3>الإدارة الحديثة للاشتراكات باستخدام takeUntilDestroyed</h3> |
| 13 | <p><strong>قيمة العداد التلقائي الآمن:</strong> {{ secureCount }}</p> |
| 14 | </div> |
| 15 | `, |
| 16 | styles: [` |
| 17 | .memory-card { background: #090d16; color: #fff; padding: 24px; border-radius: 12px; border: 1px solid #1e293b; } |
| 18 | p { color: #94a3b8; } |
| 19 | strong { color: #10b981; } |
| 20 | `] |
| 21 | }) |
| 22 | export class ModernTakeUntilDestroyedComponent implements OnInit { |
| 23 | secureCount: number = 0; |
| 24 | |
| 25 | // حقن مرجع التدمير الحديث في أنجولر |
| 26 | private destroyRef = inject(DestroyRef); |
| 27 | |
| 28 | ngOnInit(): void { |
| 29 | // ربط التدفق تلقائياً بدورة حياة المكون دون الحاجة لمتغيرات Subscription يدوية |
| 30 | interval(1000).pipe( |
| 31 | takeUntilDestroyed(this.destroyRef) |
| 32 | ).subscribe({ |
| 33 | next: (val) => { |
| 34 | this.secureCount = val; |
| 35 | console.log('قيمة العداد الآمن الحديث:', val); |
| 36 | } |
| 37 | }); |
| 38 | } |
| 39 | } |
⚠️ تحذير
احذر من استخدام takeUntilDestroyed خارج نطاق حقن المكون (Injection Context) بدون تمرير DestroyRef صريح! إذا استدعيت الدالة خارج مرحلة التهيئة أو خارج constructor/ngOnInit بدون تمرير المرجع، سيقوم نظام أنجولر بإطلاق خطأ استثناء برمجي فادح.