Subject و BehaviorSubject: شقيقان بهلوانيان في عالم البرمجة التفاعلية
\n\nإذا كنت قد ألقيت نظرة على Stack Overflow في مناقشة "ما الفرق بين Subject و BehaviorSubject؟"، فأنت تعلم أن هذا الموضوع يجمع آلاف المشاهدات. وهذا ليس مفاجئًا - فهو أحد تلك الأسئلة التي تظهر عاجلاً أم آجلاً أمام كل مطور يعمل مع RxJS في TypeScript.
\n\nتخيل أنك تدير بثًا مباشرًا للبيانات. Subject يشبه ميكروفونًا مفتوحًا: من اشترك أولاً، سيحصل على كل ما سيقال لاحقًا. أما BehaviorSubject فهو ميكروفون يحتفظ دائمًا بآخر عبارة ويعيدها فورًا للمستمع الجديد. هل تشعر بالفرق؟
\n\nفي هذه المقالة، لن نعيد سرد الوثائق فقط. سنحلل حالات حقيقية، ونعرض أمثلة على الكود بلغة TypeScript، ونقدم قواعد واضحة للاختيار. هيا بنا!
\n\nما هو Subject في TypeScript؟
\n\nSubject هو نوع خاص من Observable، وهو في نفس الوقت مراقب (Observer). يمكنه استقبال البيانات عبر طريقة next() وإرسالها إلى جميع المشتركين. لكن هناك فارق مهم: Subject لا يخزن القيم السابقة.
مثال بسيط بلغة TypeScript:
\n\nimport { Subject } from 'rxjs';\n\nconst subject = new Subject<string>();\n\n// الاشتراك بعد إرسال البيانات بالفعل\nsubject.next('الرسالة الأولى');\nsubject.next('الرسالة الثانية');\n\n// هذا المشترك لن يحصل على شيء\nsubject.subscribe({\n next: (value) => console.log('المشترك:', value)\n});\n\n// هذا سيظهر\nsubject.next('الرسالة الثالثة');\n\n\nما الذي سيظهر في وحدة التحكم؟ فقط "المشترك: الرسالة الثالثة". الرسالتان الأوليان ضائعتان إلى الأبد بالنسبة لهذا المشترك. يُسمى هذا التأثير "البداية الباردة" - تحصل فقط على البيانات التي تم إرسالها بعد الاشتراك.
\n\nBehaviorSubject: عندما تحتاج إلى تذكر الماضي
\n\nBehaviorSubject هو نفس Subject، لكن بقدرة خارقة: فهو دائمًا يخزن آخر قيمة ويقدمها للمشترك الجديد فور الاشتراك. الشرط الأساسي هو تحديد قيمة ابتدائية.
\n\nimport { BehaviorSubject } from 'rxjs';\n\nconst behaviorSubject = new BehaviorSubject<string>('قيمة ابتدائية');\n\n// الاشتراك - نحصل فورًا على آخر قيمة\nbehaviorSubject.subscribe({\n next: (value) => console.log('المشترك الأول:', value)\n});\n\nbehaviorSubject.next('التحديث الأول');\nbehaviorSubject.next('التحديث الثاني');\n\n// هذا المشترك سيحصل على 'التحديث الثاني' فورًا\nbehaviorSubject.subscribe({\n next: (value) => console.log('المشترك الثاني:', value)\n});\n\n\nالإخراج في وحدة التحكم:
\nالمشترك الأول: قيمة ابتدائية\nالمشترك الأول: التحديث الأول\nالمشترك الأول: التحديث الثاني\nالمشترك الثاني: التحديث الثاني\n\n\nهل ترى؟ المشترك الثاني حصل فورًا على آخر قيمة، على الرغم من اشتراكه لاحقًا. هذا هو الفرق الرئيسي بين BehaviorSubject و Subject.
\n\nمقارنة Subject و BehaviorSubject: جدول الاختلافات
\n\nلنلخص جميع الاختلافات في جدول توضيحي سيفيدك في المقابلة أو في مشروع حقيقي.
\n\n- \n
- القيمة الابتدائية: Subject - لا يوجد. BehaviorSubject - مطلوبة إلزاميًا. \n
- تخزين آخر قيمة: Subject - لا يخزن. BehaviorSubject - يخزن ويقدمها للمشترك الجديد. \n
- السلوك عند الاشتراك المتأخر: Subject - يتخطى جميع الأحداث السابقة. BehaviorSubject - يقدم آخر قيمة. \n
- الاستخدام مع Angular: Subject - للأحداث (النقرات، المؤقتات). BehaviorSubject - للحالة (بيانات المستخدم، الإعدادات). \n
- طريقة getValue(): Subject - غير موجودة. BehaviorSubject - موجودة، وتعيد القيمة الحالية بشكل متزامن. \n