TypeScript - مواضيع RxJS ومكونات Angular 2


أنا أتقبل حقيقة أن تطوير الويب يتغير وأنه يجب عليّ أن أتقن RxJS. أنا حاليًا أطور تطبيق ويب باستخدام Angular 2.0.0-beta.15.

أنا أتابع كتاب ng-book 2 الممتاز للغاية (هل يُسمح بهذا النوع من الإعلانات؟ على أي حال). يغطي بشكل واسع وسطحي بعض المفاهيم المهمة في RxJS ويوفر روابط لمزيد من القراءة. لقد قرأت وفهمت شفرة المصدر والشرح المرافق، لكن ما زلت غامضًا قليلاً بشأن بعض التفاصيل المتعلقة بـ Subject بشكل خاص وكيف تستهلك مكونات Angular 2 هذه التدفقات من Subject.

لقد قمت بتوسيع الكود من الكتاب على النحو التالي:

export class SubmitResourceComponent {
    private _newResourceTags: Subject<Tag> = new Subject<Tag>();
    private _resourceTags: Observable<Tag[]>;
    private _tagUpdates: Subject<any> = new Subject<any>();
    private _create: Subject<Tag> = new Subject<Tag>();
    private _remove: Subject<Tag> = new Subject<Tag>();

    constructor() {
        this._resourceTags = this._tagUpdates
            .scan((tags: Tag[], operation: ITagsOperation) => operation(tags), initialTags);

        this._create
            .map((tag: Tag): ITagsOperation => (tags: Tag[]) => _.uniq(tags.concat(tag)))
            .subscribe(this._tagUpdates);

        this._remove
            .map((tag: Tag): ITagsOperation => (tags: Tag[]) => _.without(tags, tag))
            .subscribe(this._tagUpdates);

        this._newResourceTags.subscribe(this._create);
    }

    get resourceTags(): Observable<Tag[]> {
        return this._resourceTags;
    } 

    protected addTagToResource(tag: Tag): void {
        this._create.next(tag);
    }

    protected removeTagFromResource(tag: Tag): void {
        this._remove.next(tag);
    }
}

وأنا أستهلك _resourceTags بهذه الطريقة:

<button class="btn" *ngFor="#tag of resourceTags | async" (click)="removeTagFromResource(tag)">{{ tag.name }}</button>

ما لا أستطيع فهمه، حتى مع الدعم الممتاز من منتديات gitter، هو لماذا تعرض واجهة المستخدم كل العلامات التي يتم دفعها إلى _resourceTags Subject. كنت أتخيل أن التدفق يشبه أنبوب مطاطي: بمجرد أن يتم دفع عنصر إلى Subject ونشره لأي Observer (في هذه الحالة، عنصر واجهة المستخدم)، هل لا يتبخر بعد ذلك ويختفي؟ هل يبقى في التدفق/الأنبوب/Subject؟ كيف يقوم عنصر واجهة المستخدم بالاشتراك في Subject؟ هل أفكر في الأمر بطريقة خاطئة؟ هل أحتاج إلى إعادة هيكلة ذهنية كاملة/زرع ذهني؟

الكثير من الأسئلة!

الإجابة رقم 1

البيانات التي يتم تمريرها إلى next هي مثل حدث. يحصل المشترك على القيمة، وObservable الذي تم إنشاؤه بواسطة Subject لا يحتفظ بأي مرجع لها (إلا إذا استخدمت مشغلات خاصة بهدف التخزين المؤقت أو بوسائل أخرى للاحتفاظ بالقيم المصدرة).

باستخدام | async يقوم Angular بالاشتراك في Observable (Subject) وعندما يستقبل قيمة يقوم بعرضها.

*ngFor يعرض فقط المصفوفات. إذا كنت تريد استخدام *ngFor مع Subject، يجب أن يطلق الـ Subject مصفوفات - كل حدث ليس قيمة واحدة بل مصفوفة من القيم وهذه القيم يتم عرضها بواسطة *ngFor وتستبدل بقيم أخرى عندما يطلق الـ Observable مصفوفة جديدة.

مشغل المسح

يستخدم مثال التعليمات البرمجية الخاص بك عامل scan بهدف تجميع القيم المنبعثة وتمرير مصفوفة تحتوي على جميع القيم المنبعثة حتى الآن في كل مرة يتلقى فيها حدثًا جديدًا كما هو مطلوب بواسطة *ngFor.

الإجابة رقم 2

أعتقد أن الكائنات القابلة للرصد تخزن قيم المتغير في ذاكرة المتصفح فقط حتى يتم مسح الجلسة، تمامًا كما تفعل عند إعداد متغير للحصول على قيمة من صندوق الإدخال وعند الضغط على تحديث المتصفح يتم مسح القيم. في السيناريو أعلاه، أعتقد أنه مثل معظم تطبيقات الصفحة الواحدة، يتم منع المتصفح من السلوك الافتراضي للتحديث/إعادة التحميل وتحصل على نوع من الاستمرارية، بحيث عند إجراء عملية مثل

...  _.uniq(tags.concat(tag))).subscribe(this._tagUpdates);...

تستمر القيم في التراكم حيث يتم ربطها بواسطة حدث الإنشاء لكنها تختفي عند قيام المستخدم بتحديث الصفحة يدويًا ويتم مسح الجلسة

تعديل

ربما فهمت السؤال خطأ، لكن ما أقصده هو هذا: _resourceTags يبدأ فارغًا، يتم إنشاء قيمة بواسطة حدث الإنشاء، الآن _resourceTags هو [newValue#1]، أنجولار يكتشف التغيير ويعيد عرض _resourceTags باستخدام ngFor، بعد حدث إنشاء جديد _resourceTags يصبح الآن [newValue#1, newValue#2]، أنجولار يعيد العرض ليظهر الاثنان الآن. إذا لم يتم حفظ التدفق في قاعدة بيانات على الإنترنت مثل Firebase أو قاعدة بيانات غير متصلة مثل WebSQL، فهذا يعني أنه عند إعادة تحميل المتصفح _resourceTags سيعود إلى كونه فارغًا