我正在研究Angular RxJs模式,我不明白行为主体和可观察对象之间的区别。
根据我的理解,BehaviorSubject是一个可以随时间变化的值(可以订阅,订阅者可以接收更新的结果)。这似乎与可观察对象的目的完全相同。
什么时候使用可观察对象和行为主体?使用一个行为主体比使用一个可观察对象有好处吗?反之亦然?
我正在研究Angular RxJs模式,我不明白行为主体和可观察对象之间的区别。
根据我的理解,BehaviorSubject是一个可以随时间变化的值(可以订阅,订阅者可以接收更新的结果)。这似乎与可观察对象的目的完全相同。
什么时候使用可观察对象和行为主体?使用一个行为主体比使用一个可观察对象有好处吗?反之亦然?
当前回答
我认为可观察对象是主体的包装。而Observable仅用于订阅数据更改。Subject还可以用于将数据更改通知订阅者(使用next()方法)。下面是一个小的可观察的模式实现,它可能有助于您理解这个概念。打印稿操场
其他回答
行为主体vs可观察对象:RxJS有观察者和可观察对象,RxJS提供了多个用于数据流的类,其中一个是行为主体。
可观察对象:可观察对象是多个值随时间变化的惰性集合。
BehaviorSubject:一个需要初始值并将其当前值发送给新订阅者的Subject。
// RxJS v6+
import { BehaviorSubject } from 'rxjs';
const subject = new BehaviorSubject(123);
//two new subscribers will get initial value => output: 123, 123
subject.subscribe(console.log);
subject.subscribe(console.log);
//two subscribers will get new value => output: 456, 456
subject.next(456);
//new subscriber will get latest value (456) => output: 456
subject.subscribe(console.log);
//all three subscribers will get new value => output: 789, 789, 789
subject.next(789);
// output: 123, 123, 456, 456, 456, 789, 789, 789
可观察对象只允许你订阅,而主题允许你同时发布和订阅。
因此,主题允许您的服务同时用作发布者和订阅者。
到目前为止,我不太擅长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}}
我在例子中没有看到的一件事是,当你通过asObservable将BehaviorSubject转换为Observable时,它继承了订阅时返回最后一个值的行为。
这是很棘手的一点,因为库通常会将字段作为可观察对象公开(例如,在Angular2中ActivatedRoute中的参数),但可能会在幕后使用Subject或BehaviorSubject。他们使用什么会影响订阅行为。
请看这里http://jsbin.com/ziquxapubo/edit?html,js,console
let A = new Rx.Subject();
let B = new Rx.BehaviorSubject(0);
A.next(1);
B.next(1);
A.asObservable().subscribe(n => console.log('A', n));
B.asObservable().subscribe(n => console.log('B', n));
A.next(2);
B.next(2);
把Observables想象成一个管道,里面有流动的水,有时水流动,有时不流动。在某些情况下,你可能真的需要一个一直有水的管道,你可以通过创建一个特殊的管道来做到这一点,不管它有多小,让我们把这个特殊的管道称为行为主题,如果你恰好是你所在社区的供水供应商,你可以安心地睡在晚上,因为你新安装的管道只是工作。
在技术术语中:你可能会遇到一个可观察对象总是有价值的情况,也许你想要捕获输入文本的值,然后你可以创建一个BehaviorSubject的实例来确保这种行为,让我们说:
const firstNameChanges = new BehaviorSubject("<empty>");
// pass value changes.
firstNameChanges.next("Jon");
firstNameChanges.next("Arya");
然后,您可以使用“value”对随时间变化的更改进行抽样。
firstNameChanges.value;
这在你以后组合可观察对象时很方便,通过查看你的流的类型为BehaviorSubject,你可以确保流至少会触发或发出至少一次信号。
你也可以像这样将一个主题更改为一个可观察对象:
page = new BehaviorSubject<String|null>(null);
actualPage:Observable<string> = new Observable()
this.page.next("hardware")
this.actualPage = this.page as Observable<any>;