我正在阅读这篇博客,了解Observable和Subject之间的区别,但是仍然不确定它们之间的差异。
我正在阅读这篇博客,了解Observable和Subject之间的区别,但是仍然不确定它们之间的差异。
在流编程中,有两个主要接口:Observable和Observer。
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 => ...)
或者,我们可以使用一个实现了 Observable 和 Observer 接口的 Subject:
var source = new Subject();
source.map(x => ...).filter(x => ...).subscribe(x => ...)
source.next('first')
source.next('second')
import {Observable} from 'rxjs';
let obs = new Observable<any>(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
});
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());
Observable.create
现在已被弃用,推荐使用new Observable()
。但是,使用新语法时不能调用.next()
方法。请问这种情况下的新语法是什么? - FiniteLooper可观察者
它们是冷的:只有当它们至少有一个观察者时,代码才会执行。
创建数据副本:可观察对象为每个观察者创建数据副本。
单向性:观察者不能将值分配给可观察对象(origin/master)。
代码将为每个观察者运行。如果它是HTTP调用,则会为每个观察者调用它。
如果它是我们想要在所有组件之间共享的服务,它不会具有最新结果,所有新订阅者仍将订阅同一可观察对象,并从头开始获取值。
单播意味着可以从可观察对象中发出值,而不是从任何其他组件中。
主题
它们是热的:即使没有观察者,代码也会执行并广播值。
共享数据:所有观察者之间共享相同的数据。
双向性:观察者可以将值分配给可观察对象(origin/master)。
如果使用主题,那么您会错过在创建观察者之前广播的所有值。这就是重播主题的作用。
多播,可以将值转发到多个订阅者,并且可以充当订阅者和发送者。
我觉得被接受的答案有点令人困惑!
Observer 并不是用于提供 Observable 数据源的接口,而是用于观察 Observable 数据源的接口... 从名称上更容易理解,对吧?
所以,这就是为什么:
var observable = Observable.create(observer => {
observer.next('first');
observer.next('second');
...
});
创建一个可观察对象,该对象首先发出“first”,然后发出“second”的方法是将Observable.create(...)
的参数作为订阅函数,它定义了在该Observable的直接Observer上会发生哪些Observer事件。
如果您想更深入地了解它,重要的是要理解,在订阅时,订阅函数不是在Observer对象上直接调用的,而是由一个Subscription对象进行中介,该对象可以实施正确的可观察规则,例如在调用observer.complete()
之后,即使您的订阅函数似乎会这样做,Observable也永远不会发出新值。
REF:http://reactivex.io/rxjs/manual/overview.html#creating-observables
Subject既是Observable又是Observer,再次强调,看起来就像Observer接口是'feed'事件到Subject的方法。但是如果您意识到Subject有类似于等效于订阅函数的东西(即在创建后定义观察它的事物将发生哪些事件的地方)坐在对象上,那么更容易理解命名。因此,您在Subject上调用Observer方法来定义观察它的事物将会发生哪些Observer事件!(同样,涉及中间对象,以确保您只能执行合法的一系列操作。)
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 {
//...
}
简而言之,
主题: 你可以向它发送消息并从中接收消息。
可观察对象: 你只能从中接收消息。
换句话说,在主题中,你可以随时随地使用它来订阅和广播给其他订阅者。
然而,在可观察对象中,你只能订阅它(在初始化后不能使用它广播数据)。 唯一可以从可观察对象广播数据的地方是在其构造函数中。
想象一下,如果你的应用程序中有一个数据流,例如WebSocket连接。你需要找到一种处理这些数据的方式,有几种解决方案:
1. 普通Ajax请求: 这种解决方案并不可行,因为它不能处理推送数据。它更像是拉取而不是推送。
2. Promise: 也不太好,因为你必须触发它们,并且它们只能检索一次。也更像是拉取而不是推送。
因此,在以前,为了检索这些数据,我们使用长轮询。这就是我们设置一个间隔函数,例如每1分钟检索一次该数据流的位置。虽然它起作用,但实际上会拖累资源,如CPU和内存。
但现在有了第三个选项:
3. Observable:你可以订阅并让数据流不停地进入,直到完成函数被调用。
很酷,对吧?但接着还有另一个问题:如果你只想在应用程序中的某个地方观察传入的数据一次,但想在数据到达时同时在应用程序中使用该数据,那么就可以使用Subject了。你在想要在整个应用程序中使用的位置放置subject.subscribe()。当数据到达时,任何使用subject.subscribe()的地方都将同时处理它们。但观察者必须订阅该subject作为其参数,就像这样:
观察者通过subject进行订阅(observer.subscribe(subject))。
一个例子是当你想要构建通知提醒时的应用程序。
由于每个订阅者可能会收到不同的输入数据,所以您不能多次订阅相同的observable。但是通过subject,所有通过subject订阅()的人将检索相同的数据。
另一个类比是杂志订阅。每个订阅者都会收到带有他们姓名的杂志。因此,不同的订阅=不同的接收者名称。(正常的Observable)但是当您分享给朋友时,所有朋友都只会收到带有您姓名的相同杂志。(带有Subject的普通Observable)
这位先生用代码示例很好地解释了它。您可以在此处查看。
希望这个答案有所帮助。
Observable 能够通知单个观察者,而 Subject 可以通知多个观察者。
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);
});
主题:
在构造函数之外,订阅者可以随时使用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);