我正在研究Angular RxJs模式,我不明白BehaviorSubject
和Observable
之间的区别。 css
根据个人理解, BehaviorSubject
是一个能够随时间变化的值(能够订阅,订阅者能够接收更新的结果)。 这彷佛是Observable
的彻底相同的目的。 html
你何时使用Observable
和BehaviorSubject
? 在Observable
上使用BehaviorSubject
是否有好处,反之亦然? git
Observable对象表示基于推送的集合。 github
Observer和Observable接口为基于推送的通知提供了一种通用机制,也称为观察者设计模式。 Observable对象表示发送通知的对象(提供者); Observer对象表示接收它们的类(观察者)。 ajax
Subject类继承Observable和Observer,由于它既是观察者又是observable。 您可使用主题订阅全部观察者,而后将主题订阅到后端数据源 npm
var subject = new Rx.Subject(); var subscription = subject.subscribe( function (x) { console.log('onNext: ' + x); }, function (e) { console.log('onError: ' + e.message); }, function () { console.log('onCompleted'); }); subject.onNext(1); // => onNext: 1 subject.onNext(2); // => onNext: 2 subject.onCompleted(); // => onCompleted subscription.dispose();
有关https://github.com/Reactive-Extensions/RxJS/blob/master/doc/gettingstarted/subjects.md的更多信息 后端
BehaviorSubject是一种主题,主题是一种特殊类型的可观察对象,所以您能够像任何其余可观察对象同样订阅消息。 BehaviorSubject的独特功能是: 设计模式
next()
onnext
时触发 getValue()
方法在不可观察的代码中检索主题的最后一个值。 与可观察对象相比,主题的独特特征是: angular2
此外,您可使用BehaviorSubject
上的asObservable()
方法从行为主题中获取可观察对象。 app
Observable是Generic,而BehaviorSubject
在技术上是Observable的子类型,由于BehaviorSubject是具备特定品质的可观察对象。
使用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 wont get // anything at this point }); subject.next("c"); // Subscription got c subject.next("d"); // Subscription got d
可使用subject.asObservable()
从Subject
和BehaviorSubject
建立一个observable。
惟一的区别是您没法使用next()
方法将值发送到observable。
在Angular服务中,我将使用BehaviorSubject
做为数据服务,由于角度服务一般在组件和行为主体以前初始化,即便自组件订阅此数据以来没有新的更新,消费服务的组件也会接收上次更新的数据。
一个很是重要的区别。 因为Observable只是一个函数,它没有任何状态,所以对于每一个新的Observer,它会一次又一次地执行可观察的建立代码。 这致使:
代码针对每一个观察者运行。 若是是HTTP调用,则为每一个观察者调用它
这会致使严重的错误和效率低下
BehaviorSubject(或Subject)存储观察者详细信息,仅运行一次代码并将结果提供给全部观察者。
例如:
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 │ └─────────────────────────────────────┴─────────────────────────────────────┘
我在示例中没有看到的一件事是,当您经过asObservable将BehaviorSubject强制转换为Observable时,它会继承在订阅时返回最后一个值的行为。
这是一个棘手的问题,由于一般库会将字段显示为可观察的(即Angular2中的ActivatedRoute中的params),但能够在幕后使用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);
所以,主题容许您的服务既能够用做发布者,也能够用做订阅者。
截至目前,我不太擅长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 gc components/home
以生成主组件。 用如下内容替换home.component.html
的内容:
<input type="text" placeholder="Enter message" #message> <button type="button" (click)="setMessage(message)" >Send message</button>
#message
是这里的局部变量。 添加属性message: string;
到app.component.ts
的课程。
运行此命令ng gs 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
执行此app.component.ts
。 使用此服务实例将#message
的值#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(); } }
而已。
如今,内部输入的任何值#message
的home.component.html
须印到{{message}}
内部app.component.html