我正在研究Angular RxJs模式,我不明白行为主体和可观察对象之间的区别。
根据我的理解,BehaviorSubject是一个可以随时间变化的值(可以订阅,订阅者可以接收更新的结果)。这似乎与可观察对象的目的完全相同。
什么时候使用可观察对象和行为主体?使用一个行为主体比使用一个可观察对象有好处吗?反之亦然?
我正在研究Angular RxJs模式,我不明白行为主体和可观察对象之间的区别。
根据我的理解,BehaviorSubject是一个可以随时间变化的值(可以订阅,订阅者可以接收更新的结果)。这似乎与可观察对象的目的完全相同。
什么时候使用可观察对象和行为主体?使用一个行为主体比使用一个可观察对象有好处吗?反之亦然?
当前回答
BehaviorSubject
BehaviorSubject构建在与我们的ReplaySubject相同的功能之上,比如,hot,并重放先前的值。
BehaviorSubject又增加了一个功能,您可以给BehaviorSubject一个初始值。让我们继续,看看这段代码
import { ReplaySubject } from 'rxjs';
const behaviorSubject = new BehaviorSubject(
'hello initial value from BehaviorSubject'
);
behaviorSubject.subscribe(v => console.log(v));
behaviorSubject.next('hello again from BehaviorSubject');
观察
首先,我们来看看创建常规Observable的最小API。有几种方法可以创建Observable。创建Observable的方法是实例化类。其他操作符可以简化这个步骤,但我们希望将实例化步骤与不同的Observable类型进行比较
import { Observable } from 'rxjs';
const observable = new Observable(observer => {
setTimeout(() => observer.next('hello from Observable!'), 1000);
});
observable.subscribe(v => console.log(v));
其他回答
观察:每个观察者的结果不同
一个非常非常重要的区别。因为Observable只是一个函数,它没有任何状态,所以对于每个新的Observer,它都会一次又一次地执行可观察对象的创建代码。结果是:
为每个观察者运行代码 . 如果它是一个HTTP调用,它会被每个观察者调用
这会导致主要的错误和低效率
BehaviorSubject(或Subject)存储观察者细节,只运行一次代码,并将结果提供给所有观察者。
Ex:
JSBin: http://jsbin.com/qowulet/edit?js,console
// --- Observable --- let randomNumGenerator1 = Rx.Observable.create(observer => { observer.next(Math.random()); }); let observer1 = randomNumGenerator1 .subscribe(num => console.log('observer 1: '+ num)); let observer2 = randomNumGenerator1 .subscribe(num => console.log('observer 2: '+ num)); // ------ BehaviorSubject/ Subject let randomNumGenerator2 = new Rx.BehaviorSubject(0); randomNumGenerator2.next(Math.random()); let observer1Subject = randomNumGenerator2 .subscribe(num=> console.log('observer subject 1: '+ num)); let observer2Subject = randomNumGenerator2 .subscribe(num=> console.log('observer subject 2: '+ num)); <script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.5.3/Rx.min.js"></script>
输出:
"observer 1: 0.7184075243594013"
"observer 2: 0.41271850211336103"
"observer subject 1: 0.8034263165479893"
"observer subject 2: 0.8034263165479893"
观察如何使用Observable。create为每个观察者创建了不同的输出,但BehaviorSubject为所有观察者提供了相同的输出。这很重要。
总结了其他差异。
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ Observable ┃ BehaviorSubject/Subject ┃
┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
┃ Is just a function, no state ┃ Has state. Stores data in memory ┃
┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
┃ Code run for each observer ┃ Same code run ┃
┃ ┃ only once for all observers ┃
┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
┃ Creates only Observable ┃Can create and also listen Observable┃
┃ ( data producer alone ) ┃ ( data producer and consumer ) ┃
┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
┃ Usage: Simple Observable with only ┃ Usage: ┃
┃ one Obeserver. ┃ * Store data and modify frequently ┃
┃ ┃ * Multiple observers listen to data ┃
┃ ┃ * Proxy between Observable and ┃
┃ ┃ Observer ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
BehaviorSubject是一种类型的主题,主题是一种特殊类型的可观察对象,所以你可以像其他可观察对象一样订阅消息。行为主体的独特之处在于:
它需要一个初始值,因为它必须总是在订阅时返回一个值,即使它没有接收到next() 在订阅时,它返回主题的最后一个值。常规可观察对象只有在接收到onnext时才会触发 在任何时候,您都可以使用getValue()方法在不可观察的代码中检索主题的最后一个值。
与可观察对象相比,主体的独特特征是:
它是一个观察者,除了是一个可观察对象,所以你也可以发送值到一个主题,除了订阅它。
此外,你可以使用行为主体上的asObservable()方法从行为主体获取一个可观察对象。
Observable是一个泛型,而BehaviorSubject在技术上是Observable的子类型,因为BehaviorSubject是一个具有特定品质的可观察对象。
以行为主体为例:
// Behavior Subject
// a is an initial value. if there is a subscription
// after this, it would get "a" value immediately
let bSubject = new BehaviorSubject("a");
bSubject.next("b");
bSubject.subscribe(value => {
console.log("Subscription got", value); // Subscription got b,
// ^ This would not happen
// for a generic observable
// or generic subject by default
});
bSubject.next("c"); // Subscription got c
bSubject.next("d"); // Subscription got d
例2:常规主语:
// Regular Subject
let subject = new Subject();
subject.next("b");
subject.subscribe(value => {
console.log("Subscription got", value); // Subscription won't get
// anything at this point
});
subject.next("c"); // Subscription got c
subject.next("d"); // Subscription got d
可以使用Subject . asobservable()从Subject和BehaviorSubject创建一个可观察对象。
唯一的区别是你不能使用next()方法将值发送到可观察对象。
在Angular服务中,我会为数据服务使用BehaviorSubject,因为Angular服务通常会在组件之前进行初始化,而behavior subject会确保使用该服务的组件接收到最后一次更新的数据,即使自该组件订阅该数据以来没有新的更新。
可观察对象只允许你订阅,而主题允许你同时发布和订阅。
因此,主题允许您的服务同时用作发布者和订阅者。
到目前为止,我不太擅长Observable,所以我只分享一个Subject的例子。
让我们用一个Angular CLI的例子来更好地理解。执行如下命令:
npm install -g @angular/cli
ng new angular2-subject
cd angular2-subject
ng serve
将app.component.html的内容替换为:
<div *ngIf="message">
{{message}}
</div>
<app-home>
</app-home>
执行命令ng g c components/home生成home组件。将home.component.html的内容替换为:
<input type="text" placeholder="Enter message" #message>
<button type="button" (click)="setMessage(message)" >Send message</button>
#message是这里的局部变量。添加属性消息:string; 到app.component.ts的类。
执行命令ng g s service/message。这将在src\app\service\message.service.ts上生成一个服务。向应用程序提供此服务。
将Subject导入MessageService。也要添加一个主题。最终的代码应该是这样的:
import { Injectable } from '@angular/core';
import { Subject } from 'rxjs/Subject';
@Injectable()
export class MessageService {
public message = new Subject<string>();
setMessage(value: string) {
this.message.next(value); //it is publishing this value to all the subscribers that have already subscribed to this message
}
}
现在,将这个服务注入到home.component.ts中,并将它的一个实例传递给构造函数。对app.component.ts也这样做。使用这个服务实例将#message的值传递给服务函数setMessage:
import { Component } from '@angular/core';
import { MessageService } from '../../service/message.service';
@Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.css']
})
export class HomeComponent {
constructor(public messageService:MessageService) { }
setMessage(event) {
console.log(event.value);
this.messageService.setMessage(event.value);
}
}
在app.component.ts中,向Subject订阅和取消订阅(以防止内存泄漏):
import { Component, OnDestroy } from '@angular/core';
import { MessageService } from './service/message.service';
import { Subscription } from 'rxjs/Subscription';
@Component({
selector: 'app-root',
templateUrl: './app.component.html'
})
export class AppComponent {
message: string;
subscription: Subscription;
constructor(public messageService: MessageService) { }
ngOnInit() {
this.subscription = this.messageService.message.subscribe(
(message) => {
this.message = message;
}
);
}
ngOnDestroy() {
this.subscription.unsubscribe();
}
}
就是这样。
现在,在home.component.html的#message中输入的任何值都将被打印到app.component.html中的{{message}}
可观测的 是通用的,
可观察对象是多个值随时间变化的惰性集合。
只是一个函数,没有状态
为每个观察者运行代码
BehaviorSubject: 一个需要初始值并将其当前值发送给新订阅者的主题。
在技术上是Observable的子类型,因为BehaviorSubject是一个具有特定品质的可观察对象。
有状态。在内存中存储数据
相同的代码只对所有观察者运行一次
行为主体的独特特征如下:
它需要一个初始值,因为它必须总是在订阅时返回一个值,即使它没有接收到next()
在订阅时,它返回主题的最后一个值。常规可观察对象只有在接收到onnext时才会触发
在任何时候,您都可以使用getValue()方法在不可观察的代码中检索主题的最后一个值。
你也可以像这样将一个主题更改为一个可观察对象:
page = new BehaviorSubject<String|null>(null);
actualPage:Observable<string> = new Observable()
this.page.next("hardware")
this.actualPage = this.page as Observable<any>;