在 rxjs 中,Observer 和 Subject 的区别是什么?

我正在浏览这个 博客和阅读有关可观测的东西,不能弄清楚可观测的东西和一个主题之间的区别。

91957 次浏览

在流编程中有两个主要接口: 显而易见观察者

可观察 对于消费者而言,它可以被转换和订阅:

observable.map(x => ...).filter(x => ...).subscribe(x => ...)

Observer 是用来提供可观测源的接口:

observer.next(newItem)

我们可以用 观察者创建新的 显而易见:

var observable = Observable.create(observer => {
observer.next('first');
observer.next('second');
...
});
observable.map(x => ...).filter(x => ...).subscribe(x => ...)

或者,我们可以使用同时实现 显而易见观察者接口的 主题:

var source = new Subject();
source.map(x => ...).filter(x => ...).subscribe(x => ...)
source.next('first')
source.next('second')

参见 rxjs 文档(更多信息和示例) : Http://reactivex.io/rxjs/manual/overview.html#subject

主题是什么?RxJS Subject 是一种特殊类型的 Observer,它允许将值多播给许多观察者。普通的观察者是单播的(每个订阅的观察者都有一个独立的观察者执行) ,而主体是多播的。

一个 Subject 类似于可观察的,但是可以多播给许多观察者。主题类似于 EventEmitters: 它们维护许多侦听器的注册表。

和代码,Subject扩展 Observable: https://github.com/ReactiveX/rxjs/blob/master/src/internal/Subject.ts#L22

/**
* @class Subject<T>
*/
export class Subject<T> extends Observable<T> implements SubscriptionLike {
//...
}

从另一个角度来看,值得注意的是,对 重新执行可观察函数的订阅。如果数据源是一个例如服务的数据源,那么这会导致性能问题。

如果希望多个订阅者获得相同的值,则可能需要 Subject 。 为此,请确保将订阅设置为 之前,即订阅数据源的 Subject。否则,您的过程将被卡住。

详情请浏览这里: https://javascript.tutorialhorizon.com/2017/03/23/rxjs-subject-vs-observable/

观察者只能通知一个观察者,而主体可以通知多个观察者。

可观察到的

  1. 它们是冷的: 代码在至少有一个观察者时执行。

  2. 创建数据副本: Observer 为每个观察者创建数据副本。

  3. 单向: 观察者不能为可观察的(原点/主点)赋值。

  4. 代码将为每个观察者运行,如果是 HTTP 调用,则为每个观察者调用。

  5. 如果它是一个我们想要在所有组件之间共享的服务,它不会有最新的结果,所有的新订阅者仍然会订阅相同的可观察到的,并从头开始获得价值

  6. Unicast 意味着可以从可观察的组件发出值,而不是从任何其他组件发出值。

主题

  1. 它们非常热门: 即使没有观察者,代码也会被执行,值也会被广播。

  2. 共享数据: 所有观察者共享相同的数据。

  3. 双向: 观察者可以为可观察的(原点/主点)赋值。

  4. 如果使用 subject,那么您将错过在创建 Observer 之前广播的所有值。重放主题

  5. 多播,可以向多个订阅方强制转换值,并且可以同时作为订阅方和发射方

想象一下,如果有一个数据流进入您的应用程序,就像在一个 websocket 连接中一样。你想要一个办法来处理它。有一些解决办法:

1. 普通 ajax 请求: 这个解决方案不可行,因为它是可行的 不适用于处理推送数据 用力。

2. 承诺: 也不好,因为你必须触发他们 它们只能恢复一次,而且拉力大于推力。

因此,为了检索这些数据,在过去,我们做了一个长期轮询。在这里,我们设置了一个间隔函数,以每1分钟检索一次示例数据流。虽然它可以工作,但它实际上加重了 CPU 和内存等资源的负担。

但现在有了第三种选择,

3. 可观察: 你可以订阅并让数据流来 直到函数完成被调用为止。

酷吧?但还有一个问题。如果您只想在应用程序的某个位置观察传入的数据一次,该怎么办。但是,当数据到达时,您希望在应用程序周围同时使用该数据。这是您使用 Subject 的时间和地点。 将 subject.scrib ()放置在希望在整个应用程序中使用的位置。当数据到达时,subject.ordering ()将同时处理这些数据。但是观察者必须赞同主体的论点,就像这样。

订阅(主题)。

示例应用程序是当您希望生成通知警报时。

您不能拥有同一个可观察数据的多个订阅,因为每个订阅者很可能会收到不同的输入数据。但是对于 subject,所有通过 subject 订阅()的操作都将检索相同的数据。

另一个类比是通过订阅杂志。每个订阅者都会收到印有自己名字的杂志。因此,不同的订阅 = 不同的接收方名称。(正常值) 但是当你和你的朋友分享时,你所有的朋友都会收到同一本杂志,上面只有你的名字。(科目正常)

这个人用代码示例很好地解释了它,你可以在 https://javascript.tutorialhorizon.com/2017/03/23/rxjs-subject-vs-observable/上查看

希望这个答案能有所帮助。

我发现接受的答案有点令人困惑!

一个 观察者 不是的接口供应一个 显而易见源,它的接口为 观察一个 显而易见源... 这是更有意义的名称,对不对?

原因是:

var observable = Observable.create(observer => {
observer.next('first');
observer.next('second');
...
});

工程-创建一个可观察的发射’第一’,然后’第二’-是参数的 Observable.create(...)是一个 订阅功能,它基本上定义了哪些 观察者事件将发生在直接 观察者显而易见

如果你想再深入一点,重要的是要理解订阅函数 不是在你订阅时直接调用 观察者对象,而是由一个 订阅对象调用,它可以强制执行正确的可观察规则,例如,一个 显而易见将永远不会发出一个新的值在 observer.complete()被调用后,即使你的订阅函数看起来像它会。

参考资料: http://reactivex.io/rxjs/manual/overview.html#creating-observables

主题既是一个 显而易见也是一个 观察者,它同样是 看起来,就像 观察者接口一样,是向 主题“提供”事件的方式。但是如果你意识到一个 主题有点像一个相当于订阅函数的 显而易见(也就是你定义观察它的东西会发生什么事情) ,即使在它被创建之后,它仍然坐落在对象上,那么你就更容易理解它的命名。因此,您可以在 主题上调用 观察者方法来定义观察到的事件上将发生什么 观察者事件!(同样,还涉及到中间对象,以确保您只能执行合法的事情顺序。)

参考资料: http://reactivex.io/rxjs/manual/overview.html#subject

可观测内容按设计单播,主题按设计多播。

如果你看下面的例子-每个订阅接收不同的值作为设计为单播的观察值。

import {Observable} from 'rxjs';


let obs = Observable.create(observer=>{
observer.next(Math.random());
})


obs.subscribe(res=>{
console.log('subscription a :', res); //subscription a :0.2859800202682865
});


obs.subscribe(res=>{
console.log('subscription b :', res); //subscription b :0.694302021731573
});

如果您期望两个订阅都有相同的值,那么这可能很奇怪。

我们可以通过使用 Subject主题类似于事件发射器,它不为每个订阅调用。来克服这个问题。

import {Subject} from 'rxjs';


let obs = new Subject();


obs.subscribe(res=>{
console.log('subscription a :', res); // subscription a : 0.91767565496093
});


obs.subscribe(res=>{
console.log('subscription b :', res);// subscription b : 0.91767565496093
});


obs.next(Math.random());

两个订阅都得到了相同的输出值。

可观察 : 只有被观察者知道事件是如何以及何时在被观察者身上触发的。即 next()方法只能在实例化的构造函数中调用。此外,在每次订阅时,都会创建一个单独的观察器,并且只在构造函数内使用特定的观察器调用 next()方法,在下面的示例中,subscriber本身就是观察器,并且在实例化的构造函数执行时被订阅。 例如:

import { Observable } from 'rxjs';


const observable = new Observable(subscriber => {
subscriber.next(1);
subscriber.next(2);
setTimeout(() => {
subscriber.next(3);
}, 1000);
});

主题 : 这里 next()方法可以由 subject 在构造函数之外的任何地方使用。另外,在订阅之前调用 next()方法时,将错过特定的事件。因此,只有在订阅之后才能调用 next()方法。 例如:

import { Subject } from 'rxjs';
 

const subject = new Subject<number>();
 



subject.next(1); // this is missed
subject.subscribe({
next: (v) => console.log(`observerA: ${v}`)
});
subject.subscribe({
next: (v) => console.log(`observerB: ${v}`)
});
subject.next(2);

简而言之,

主题 : 你可以从 发送到它,从 接收到它。

可观察 : 你可以从它 接收

换句话说, 在 主题你可以 订阅到它 还有你可以使用它到 广播到其他订阅者在任何时间和任何地方的代码。

同时, 在 显而易见你可以 订阅到它 只有(你不能使用它广播数据后,它已经初始化)。 只有在它的构造函数中才能从可观测数据广播数据。