| وجه المقارنة المعمارية | التسجيل عبر نطاق الجذر (providedIn: 'root') | التسجيل داخل مصفوفة providers للمكون |
|---|---|---|
| نطاق حياة الخدمة وتواجدها | تبقى الخدمة حية وفعالة طوال فترة تشغيل التطبيق بالكامل (Singleton) | تتولد نسخة جديدة مع كل عملية فتح للمكون وتُدمر فور تدميره |
| استهلاك الذاكرة وإدارتها | منخفض جداً ومحسّن، حيث يتم مشاركة نفس النسخة بين كافة مكونات النظام | أعلى نسبياً إذا تكرر فتح المكونات وإغلاقها بشكل مستمر |
| قابلية الحذف الشجري (Tree-shaking) | مدعومة بالكامل، وإذا لم يتم استدعاء الخدمة يتم حذفها من الحزمة النهائية تلقائياً | غير مدعومة، حيث تُجبر أنگولر على إبقاء الخدمة ضمن الكود النهائي للتطبيق |
عندما نتحدث عن إدارة الخدمات وحقن التبعيات في Angular 22.1، تبرز الخاصية المعمارية providedIn: 'root' كواحدة من أهم أدوات تحسين الأداء وحفظ الذاكرة. هذه الخاصية تبلغ نظام أنگولر بضرورة إنشاء نسخة واحدة فقط وعامة (Singleton Instance) من الخدمة على مستوى التطبيق بأكمله، مما يلغي الحاجة لتسجيلها يدوياً في مصفوفات المزودين ويسمح بنظام الحذف الشجري الأمثل (Tree-shaking) للكود غير المستخدم.
عند استخدام providedIn: 'root', يضمن أنگولر عدم تكرار إنشاء الخدمة أبداً. هذا يعني أن البيانات المخزنة داخل هذه الخدمة تظل ثابتة ومشارِكة بين جميع المكونات والشاشات في التطبيق دون فقدان حالتها عند التنقل.
في الإصدارات الحديثة، يتيح هذا النمط لمترجم أنگولر اكتشاف ما إذا كانت الخدمة مستخدمة حقاً في الكود أم لا. إذا لم يتم حقنها في أي مكان، يتم إزالتها كلياً من الملفات النهائية (Production Bundles)، مما يقلل حجم التطبيق ويزيد من سرعة تحميله.
| 1 | import { Injectable, signal } from '@angular/core'; |
| 2 | |
| 3 | @Injectable({ |
| 4 | providedIn: 'root' |
| 5 | }) |
| 6 | export class GlobalAppConfigService { |
| 7 | private appVersionSignal = signal<string>('v22.1.0-Enterprise'); |
| 8 | private maintenanceModeSignal = signal<boolean>(false); |
| 9 | |
| 10 | readonly appVersion = this.appVersionSignal.asReadonly(); |
| 11 | readonly isMaintenanceMode = this.maintenanceModeSignal.asReadonly(); |
| 12 | |
| 13 | toggleMaintenance() { |
| 14 | this.maintenanceModeSignal.update(status => !status); |
| 15 | } |
| 16 | } |
| 1 | <!-- app-config-status.component.html --> |
| 2 | <div class="config-panel"> |
| 3 | <h3>لوحة إعدادات النظام العامة (Root Scope)</h3> |
| 4 | |
| 5 | <div class="status-box" [ngClass]="configService.isMaintenanceMode() ? 'offline' : 'online'"> |
| 6 | <p><strong>إصدار المعمارية الحالي:</strong> {{ configService.appVersion() }}</p> |
| 7 | <p><strong>حالة خوادم النظام:</strong> |
| 8 | <span>{{ configService.isMaintenanceMode() ? 'وضع الصيانة نشط' : 'النظام يعمل بكفاءة تامة' }}</span> |
| 9 | </p> |
| 10 | </div> |
| 11 | |
| 12 | <button (click)="configService.toggleMaintenance()" class="toggle-config-btn"> |
| 13 | تبديل حالة الصيانة العامة |
| 14 | </button> |
| 15 | </div> |
⚠️ تحذير
جنب إسقاط نطاق الجذر (providedIn: 'root') في الخدمات ذات الحالة المؤقتة! إذا كانت الخدمة مسؤولة عن إدارة بيانات خاصة بمكون محدد أو نافذة منبثقة مؤقتة ويجب تدميرها فور إغلاق هذا المكون لتفريغ الذاكرة، فلا تستخدم providedIn: 'root'. في هذه الحالة، قم بتسجيل الخدمة محلياً داخل مصفوفة providers الخاصة بالمكون نفسه لضمان إنشاء نسخة جديدة ومستقلة وتدميرها بانتهاء دورة حياة المكون.
| 1 | /* app-config-status.component.css */ |
| 2 | .config-panel { |
| 3 | background: #090d16; |
| 4 | color: #ffffff; |
| 5 | padding: 24px; |
| 6 | border-radius: 12px; |
| 7 | border: 1px solid #334155; |
| 8 | } |
| 9 | |
| 10 | .status-box { |
| 11 | background: #1e293b; |
| 12 | padding: 16px; |
| 13 | border-radius: 8px; |
| 14 | margin: 16px 0; |
| 15 | border: 1px solid #475569; |
| 16 | } |
| 17 | |
| 18 | .status-box.online { border-right: 5px solid #34d399; } |
| 19 | .status-box.offline { border-right: 5px solid #f87171; } |
| 20 | |
| 21 | .toggle-config-btn { |
| 22 | background: #38bdf8; |
| 23 | color: #090d16; |
| 24 | border: none; |
| 25 | padding: 10px 20px; |
| 26 | border-radius: 6px; |
| 27 | font-weight: bold; |
| 28 | cursor: pointer; |
| 29 | } |
| 30 | |
| 31 | .toggle-config-btn:hover { |
| 32 | background: #7dd3fc; |
| 33 | } |
| 1 | import { Component, inject } from '@angular/core'; |
| 2 | import { CommonModule } from '@angular/common'; |
| 3 | import { GlobalAppConfigService } from './global-app-config.service'; |
| 4 | |
| 5 | @Component({ |
| 6 | selector: 'app-config-status', |
| 7 | standalone: true, |
| 8 | imports: [CommonModule], |
| 9 | templateUrl: './app-config-status.component.html', |
| 10 | styleUrls: ['./app-config-status.component.css'] |
| 11 | }) |
| 12 | export class ConfigStatusComponent { |
| 13 | // حقن الخدمة المسجلة في الجذر للاستفادة من النطاق العام |
| 14 | readonly configService = inject(GlobalAppConfigService); |
| 15 | } |