繁体   English   中英

rxjs 中的 Observable 和 Subject 有什么区别?

[英]What is the difference between Observable and a Subject in rxjs?

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

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

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

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

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

observer.next(newItem)

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

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

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

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

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
});

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

我们可以使用 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());

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

可观察对象

  1. 他们很冷漠:当他们至少有一个观察者时,代码就会被执行。

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

  3. 单向:Observer 不能为 observable(origin/master)赋值。

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

  5. 如果它是我们想要在所有组件之间共享的服务,它不会有最新结果所有新订阅者仍将订阅相同的 observable 并从头开始获取价值

  6. 单播意味着可以从 observable 发出值,而不是从任何其他组件发出值。

主题

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

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

  3. 双向:Observer 可以为 observable(origin/master) 赋值。

  4. 如果使用 using 主题,那么您将错过在创建观察者之前广播的所有值。 所以这里来了重播主题

  5. 多播,可以将值投射到多个订阅者,并且可以同时充当订阅者和发射者

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

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

一个 Subject 就像一个 Observable,但可以多播给许多观察者。 主题就像 EventEmitters:它们维护着许多侦听器的注册表。

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

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

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

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

Observer不是用于提供Observable源的接口,而是用于观察Observable源的接口……从名称上看更有意义,对吗?

所以,原因是:

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

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

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

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

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

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

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

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

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

想象一下,如果您有一个数据流进入您的应用程序,就像在 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/查看

希望这个答案有帮助。

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);
});

Subject :这里的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);

简要地,

主题:您可以发送到它并从中接收

观察到的:你可以从它只能接收

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

同时,在观察到只能订阅(它初始化之后,你不能用它来广播数据)。 唯一可以从 observable 广播数据的地方是它的构造函数内部。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM