rxjs中Observable和Subject之间有什么区别?

Lij*_*raj 20 javascript reactive-programming rxjs angular

我正在浏览这个博客并阅读有关Observables的内容,我无法弄清楚Observable与Subject之间的区别

jai*_*aji 103

Observable 设计为单播,Subjects 设计为多播。

如果您查看下面的示例 -每个订阅都会收到不同的值作为设计为单播开发的 observable。

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
});
Run Code Online (Sandbox Code Playgroud)

如果您期望订阅的值相同,这可能会很奇怪。

我们可以使用 Subjects 来解决这个问题。主题类似于事件发射器,它不会为每个订阅调用。考虑下面的例子。

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());
Run Code Online (Sandbox Code Playgroud)

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

  • 用随机值来演示确实是个好主意,比仅仅引用单播/多播要好得多。 (16认同)

Zah*_*hiC 31

在流编程中有两个主要接口:ObservableObserver.

Observable是针对消费者的,它可以被转换和订阅:

observable.map(x => ...).filter(x => ...).subscribe(x => ...)
Run Code Online (Sandbox Code Playgroud)

Observer是用于提供可观察源的接口:

observer.next(newItem)
Run Code Online (Sandbox Code Playgroud)

我们可以使用Observer创建新的Observable:

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

或者,我们可以使用实现ObservableObserver接口的Subject:

var source = new Subject();
source.map(x => ...).filter(x => ...).subscribe(x => ...)
source.next('first')
source.next('second')
Run Code Online (Sandbox Code Playgroud)

  • 完美的解释。+1 对于代码示例,专门使用观察者创建可观察的。 (3认同)

小智 17

简要地,

subject:您可以向其发送并从中接收。

Observable:您只能从中接收

换句话说,在主题中你可以订阅,并且你可以使用它在代码中随时随地向其他订阅者广播。

而在observable中,您只能订阅(初始化后不能使用它来广播数据)。唯一可以从 observable 广播数据的地方是在它的构造函数内部。


小智 11

Observable 只能通知一个观察者,而 Subject 可以通知多个观察者。


Mik*_*ton 11

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

一个观察员 用于喂养的接口可观察源,它是接口观察可观察源...这使得从名字更有意义吧?

所以,原因是:

var observable = Observable.create(observer => { 
    observer.next('first'); 
    observer.next('second'); 
    ... 
});
Run Code Online (Sandbox Code Playgroud)

工作 - 创建一个发出“第一个”然后“第二个”的 observable - 的参数Observable.create(...)subscribe 函数,它基本上定义了哪些Observer事件将在该Observable的直接Observer上发生。

如果你想再深入一点,重要的是要理解订阅函数在你订阅时不是直接在Observer对象上调用的,而是由一个Subscription对象中介,它可以强制执行正确的可观察规则,例如一个可观察绝不会发出一个新的值之后observer.complete()被调用,即使你的订阅功能,看起来好像会。

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

一个主题既是可观察观测,并再次它看起来就像观察接口的方式,以“饲料”事件的主题。但是,如果您意识到Subject有点像Observable并具有与 subscribe 功能等效的Observable(即您定义观察它的事物将发生什么事件),则它更容易理解命名坐在对象上,即使在它之后已经被创造了。所以,你在Subject上调用Observer方法来定义什么Observer事件会发生在观察它的事物上!(同样,涉及中间对象,以确保您只能做合法的事情序列。)

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

  • 阅读已接受的答案后,我也很困惑,想知道是否只有我或其他人也对此不满意。感谢您发表您的想法。 (4认同)

Joh*_*ith 10

请参阅rxjs文档(此处有更多信息和示例):http ://reactivex.io/rxjs/manual/overview.html#subject

什么是主题?RxJS主题是一种特殊的Observable类型,它允许将值多播到许多Observer。普通的Observable是单播的(每个订阅的Observer拥有Observable的独立执行),而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 {
//...
}
Run Code Online (Sandbox Code Playgroud)


小智 8

可观察的

  1. 它们很冷:只有至少一个观察者时,代码才能执行。

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

  3. 单向:观察者无法将值分配给可观察(原始/主)。

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

  5. 如果它是我们希望在所有组件之间共享的服务,它将不会有最新的结果,所有新订户仍将订阅相同的可观察的内容并从头开始获得价值

  6. 单播装置可以从可观察到的而不是从任何其他组件发出值。

学科

  1. 它们很热:即使没有观察者,代码也会被执行,价值也会得到传播。

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

  3. 双向:观察者可以将值分配给可观察(原始/主)。

  4. 如果正在使用主题,则您会错过创建观察者之前广播的所有值。所以这是重播主题

  5. multicast, can cast values to multiple subscribers and can act as both subscribers and emmitter


Vin*_*com 6

从另一个角度来看,注意到订阅一个 Observable 会重新执行 Observable 函数是好的。例如,如果数据源是服务,这可能会导致性能问题。

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

更多细节在这里:https : //javascript.tutorialhorizo​​n.com/2017/03/23/rxjs-subject-vs-observable/


Api*_*ail 6

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

1.普通ajax请求: 这个方案不可行,因为不适用于处理推送数据。与其说是推,不如说是拉。

2. Promise: 也不好,因为你必须触发它们并且它们只能检索一次。也更多的是拉然后推。

所以为了取回这些数据,在过去,我们做一个长轮询。例如,我们在这里设置了一个间隔函数来每 1 分钟检索一次该数据流。虽然它有效,但它实际上加重了 CPU 和内存等资源的负担。

但现在有了选项 3,

3. Observable:你可以订阅并让数据流不停地进来,直到函数完成被调用。

酷吧?但是还有另一个问题。如果您只想在应用程序中的某处观察一次传入数据,该怎么办?但是您希望在数据到达时在您的应用程序周围同时使用该数据。那是您何时何地使用主题。您将 subject.subscribe() 放在要在整个应用程序中使用的地方。当数据到达时,有subject.subscribe() 的地方会同时处理它们。但是观察者必须像这样订阅主题作为其参数。

观察者.订阅(主题)。

示例应用程序是当您想要构建通知警报时。

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

另一个类比是通过杂志订阅。每个订阅者都会收到带有他们名字的杂志。所以,不同的订阅 = 不同的接收者姓名。(Normal Observable)但是当你与你的朋友分享时,你所有的朋友都会收到同样的杂志,上面只有你的名字。(Normal Observable with Subject)

这家伙用代码示例很好地解释了它。您可以在https://javascript.tutorialhorizo​​n.com/2017/03/23/rxjs-subject-vs-observable/查看

希望这个答案有帮助。


muk*_*lam 5

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

import { Observable } from 'rxjs';

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

主体next()主体可以在构造函数之外的任何地方使用此方法。此外,当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);
Run Code Online (Sandbox Code Playgroud)