订阅 Observable 与订阅 Subject

Subscribe to Observable vs subscribe to Subject

在 Angular 应用程序中有多种从服务器获取数据的方法:

  1. 从服务获取 Observable 并在组件订阅它
  2. 在服务创建Subject,在组件订阅Subject

这两种方法对我都适用,但我不知道应该使用哪种。

第一种方法从服务获取 Observable 并在组件订阅它:

article.service.ts

import { Injectable } from '@angular/core';
import { Article } from '../models/article';
import { AngularFirestore } from '@angular/fire/firestore';
import { map, take } from 'rxjs/operators';
import { Observable, Subject } from 'rxjs';

@Injectable({
  providedIn: "root"
})
export class ArticleService {
  public articlesChanged: Subject<Article[]> = new Subject<Article[]>();
  articles: Article[];

  constructor(private db: AngularFirestore) {}

  get() {
    return this.db.collection('articles').valueChanges({ idField: 'id' });
  }
}

home.component.ts

import { Component, OnInit } from '@angular/core';
import { ArticleService } from 'src/app/services/article.service';
import { Observable, Subscription } from 'rxjs';
import { Article } from 'src/app/models/article';

@Component({
  selector: 'app-home',
  templateUrl: './home.component.html',
  styleUrls: ['./home.component.scss']
})

export class HomeComponent implements OnInit {
  articles: Article[];

  constructor(private articlesService: ArticleService) { }

  ngOnInit() {
    this.articlesService.get().subscribe(articles => this.articles = articles as Article[]);
  }
}

第二种方法。在服务处创建Subject,并在组件处订阅Subject:

article.service.ts

import { Injectable } from '@angular/core';
import { Article } from '../models/article';
import { AngularFirestore } from '@angular/fire/firestore';
import { map, take } from 'rxjs/operators';
import { Observable, Subject } from 'rxjs';

@Injectable({
  providedIn: "root"
})
export class ArticleService {
  public articlesChanged: Subject<Article[]> = new Subject<Article[]>();
  articles: Article[];

  constructor(private db: AngularFirestore) {}

  get(): void {
    this.db
      .collection('articles')
      .valueChanges({ idField: 'id' }).subscribe(articles => {
        this.articles = articles as Article[];
        this.articlesChanged.next(this.articles);
      });
  }
}

home.component.ts

import { Component, OnInit, OnDestroy } from '@angular/core';
import { ArticleService } from 'src/app/services/article.service';
import { Observable, Subscription } from 'rxjs';
import { Article } from 'src/app/models/article';

@Component({
  selector: 'app-home',
  templateUrl: './home.component.html',
  styleUrls: ['./home.component.scss']
})

export class HomeComponent implements OnInit, OnDestroy {
  articlesSubscription: Subscription;
  articles: Article[];

  constructor(private articlesService: ArticleService) { }

  ngOnInit() {
    this.articlesSubscription = this.articlesService.articlesChanged.subscribe(articles => this.articles = articles);
    this.articlesService.get();
  }

  ngOnDestroy(): void {
    this.articlesSubscription.unsubscribe();
  }
}

是否有我应该使用的最佳实践?

We can say that Subject is a special type of Observable.

Observable:订阅它获取值。

Subject:相同,但您 也可以控制 您想要发送到其中的值(可以订阅它,但也emit) 你会得到默认值。

为了理解 Subject 和 Observable 之间的区别,您需要了解两个不同的概念

  • 数据生产者
  • 数据消费者

根据定义,可观察对象是数据生产者。也就是一种可以随时间产生数据的特殊类型。

另一方面,Subject 可以充当 – 数据生产者和数据消费者

这意味着两件事。

  1. Subject 可以订阅,就像 Observable 一样。
  2. 一个主题还可以订阅其他可观察对象。

也就是说,主题和可观察对象之间存在一个主要区别。

All subscribers to a subject share the same execution of the subject. i.e. when a subject produces data, all of its subscribers will receive the same data. This behavior is different from observables, where each subscription causes an independent execution of the observable.

在你的情况下,这可能没有太大区别。 但是,我可以看到使用主题会导致额外的处理,您首先通过 valueChanges 订阅获取数据,然后将其推送到主题中,然后从主题中提取数据。这看起来没有必要。

但是,想一想另一个需要与您从 db valueChanges 订阅中获得的数据相同的数据的组件。在这种情况下,您首先从源收集数据,将其推送到主题中,然后订阅同一主题的多个组件都将获取数据。 然后每个组件都可以独立处理数据并做他们的事情。

举个例子,假设一个组件触发了一些变化。结果,发生了一些处理(比如在后端)并且数据返回到包含主题的服务。数据现在被推送到主题,并且由于多个组件订阅了这个主题,所以它们都获得了相同的数据。

如您所见,这对于组件以松散耦合的方式相互通信非常有帮助。您可以使用这种方法创建一个松散耦合、灵活、可扩展的系统。