使用 Subject 和 Observable 之间有什么区别,它们的用途是什么?

What are the differences between using a Subject and an Observable, and what are the uses for each?

我已经了解了制作 Observable 的两种不同方法。第一个是主题,像这样:

// file A
const message$ = new Subject();

// file B
message$.subscribe( (message) => console.log(message) );

// file C
message$.next("Hello there!");

这种创建 Observable 的方法让我有办法将数据从文件 B 交换到文件 C。

第二种方式是通过 Observable class,像这样:

// file A
const click$ = new Observable( function(observer) { 
  //Alternatively, I can use Observable.create()
  document.addEventListener('click', (e) => observer.next(e));
});

// file B
click$.subscribe( (cl) => console.log(cl) );

我能收集到的 Subject 方式和 Observable 方式之间的主要区别是我不确定如何在某些文件 C 与 Observable 的订阅者之间进行某种通信。基本上,click$ 没有 .next() 方法,观察者方法在我们传递给可观察对象的函数中。

除了这种行为差异之外,使用 Subject 和使用 Observable 制作的 Observable 之间还有其他区别吗

Subject 实现了 Observable 和 Observer 接口。

实现 Observable 接口意味着,除其他外,您可以 subscribe 到 Subject。

实现 Observer 接口意味着,除其他外,您可以使用 Subject 调用方法 next errorcomplete.

如果您想以编程方式控制该 Observable 的事件流,您可以使用 Subject 创建 Observables,这就是您提到的管理 CB.

SubjectObservable的关系是这样的:

class Observable {}

class Subject extends Observable {}

Subject 实现了 Subscriber 接口。所以你可以使用 Subject 作为 SubscriberObservable 不能这样使用):

const subj = new Subject()
observable.subscribe(subj)

Subject 可以通过调用 asObservable 方法隐藏它的 Subscriber 接口 - 将 Subject 变成普通的 Observable;


我通常在我的代码要生成事件时使用 Subject,而当我已经有一些事件源时我使用 Observable

例如使用 Subject 作为队列:

const queue = new Subject();

queue.pipe(
  concatMap(doStuff)
).subscribe()

queue.next('do this')
queue.next('do that')

或者使用 Subject 作为信号器来停止其他 Observable

const stop = new Subject();

someObservable.pipe(
  map(x => x + 1)
  takeUntil(stop)
)

// somewhere in my code
stop.next()

Other than this difference in behavior, is there another difference between observables made with Subject, and those made with Observable

我不会说有差异 - 它更像是 Subject 是对普通 Observable 的补充 - 允许我们在需要时做更多事情。

一个Subject同时是ObservableObserver。这使得它非常容易使用,因为您获得了对 Observer 的引用,您可以在代码中传递它并从任何您想要的地方发出项目。但是,当您从 Observable 的声明式定义切换到命令式定义时,这会大大增加代码的错误倾向。

一般来说,您应该尽可能使用 Observable 创建函数 (of, from, create)。我会说大多数情况都可以在没有主题的情况下解决。但是有一个陡峭的学习曲线,因为您必须了解大多数 Observable 创建函数才能遵循该模式。

对于习惯于命令式编码(即:使用像 JS 这样的脚本语言)的开发人员来说,Subject 可能更自然,因为它有点类似于回调函数的简单包装对象。有人可能会问,如果它不受欢迎,为什么还要有一个 Subject。

根据这个article,主题只能在一种情况下使用:

To generate a hot observable imperatively and statefully, without any direct external source.

简而言之,这意味着:当您没有任何外部源(如 Observable、Promise 或 Event)并且需要从函数内部多播 class 的状态时,请使用 Subject。但是,您不应该向其他人公开该 Subject!

我建议你阅读这篇文章,它会把事情弄清楚。