BehaviorSubject
和Observable
之间的区别。据我所知,
BehaviorSubject
是随时间变化的值(可以订阅订阅者可以接收更新的结果)。这似乎与Observable
的目的完全相同。 什么时候使用
Observable
和BehaviorSubject
?与BehaviorSubject
相比,使用Observable
有好处吗?反之亦然?#1 楼
BehaviorSubject是主题的一种,主题是可观察的特殊类型,因此您可以像其他任何可观察对象一样订阅消息。 BehaviorSubject的独特功能是:它需要一个初始值,因为即使未收到
next()
,它也必须始终在订阅时返回一个值订阅后,它返回主题的最后一个值。常规可观察对象仅在收到
onnext
时才会触发,您可以使用getValue()
方法以不可观察的代码检索主题的最后一个值。与可观察对象相比,主题的独特特征是:
它不仅是可观察对象,而且是观察者,因此您除了订阅它之外还可以将值发送给对象。 br />
另外,您可以使用
asObservable()
上的BehaviorSubject
方法从行为主体中获得可观察到的信息。 Observable是泛型,而
BehaviorSubject
在技术上是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 wont get
// anything at this point
});
subject.next("c"); // Subscription got c
subject.next("d"); // Subscription got d
可以使用
Subject
从BehaviorSubject
和subject.asObservable()
创建一个可观察对象。 唯一的区别是您无法使用
next()
方法将值发送给可观察对象。在Angular服务中,我经常将
BehaviorSubject
用于数据服务作为角度服务在组件和行为主题之前进行初始化,以确保使用该服务的组件可以接收到最后更新的数据,即使自该组件订阅该数据以来没有新的更新也如此。#2 楼
可观察:每个观察者的结果不同一个非常非常重要的区别。由于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 ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
评论
与Rx.Observable相比,来自KnockoutJS的ko.observable()的任何人都将立即看到与Rx.BehaviorSubject更多的相似之处。
–Simon_Weaver
17年6月21日在21:57
@Skeptor Observable:subscribe方法将始终触发与观察者关联的onNext方法并带来返回值。 BehaviourSubject / Subject:将始终返回流中的最新值。在此,带有主题的订阅方法将不会触发其Observer的onNext方法,直到它在流中找到最新值为止。
– Mohan Ram
17-10-26在10:58
#3 楼
可观察者和对象都是可观察者,意味着观察者可以跟踪它们。但是它们都有一些独特的特征。此外,共有3种类型的主题,每个主题又具有独特的特征。让我们尝试理解它们中的每一个。您可以在stackblitz上找到实际示例。
(您需要检查控制台以查看实际输出)
Observables
它们很冷:代码被执行当他们至少有一个观察者时。
创建数据副本:Observable为每个观察者创建数据副本。
单向:观察者无法将值分配给observable (来源/主数据)。
Subject
它们很热:即使没有观察者,代码也将被执行且价值得到传播。
数据:所有观察者之间共享相同的数据。
双向:观察者可以将值分配给observable(来源/主对象)。
如果使用主题,则您会错过创建观察者之前广播的所有值。因此,重播主题出现在这里
ReplaySubject
它们很热:即使没有观察者,代码也将被执行并且价值得到传播。
共享数据:相同的数据将在所有观察者之间共享。
双向:观察者可以将值分配给observable(来源/主数据)。加
重播消息流:无论您何时订阅重播主题,您都将收到所有广播的消息。
在主题和重播主题中,您无法设置初始值可以观察到。因此,这是行为主题。
BehaviorSubject
它们很热:即使没有观察者,代码也会被执行,价值也会得到传播。
共享数据:相同的数据将在所有观察者之间共享。
双向:观察者可以将值分配给observable(来源/主数据)。加
重播消息流:无论您何时订阅重播主题,您都将收到所有广播的消息。
您可以设置初始值:可以使用默认值初始化可观察对象。
评论
值得一提的是,ReplaySubject具有历史记录,并且可以广播/发射一系列(旧)值。仅当buffer设置为1时,它的行为才类似于BehaviorSubject。
–狂野
19年11月19日在8:29
对于BehaviorSubject,“重放消息流”段落似乎不正确
– Jaqen H'ghar
12月19日7:48
#4 楼
Observable对象表示基于推送的集合。Observer和Observable接口提供了基于推送的通知的通用机制,也称为观察者设计模式。 Observable对象代表发送通知的对象(提供者); Observer对象表示接收它们的类(观察者)。
Subject类既继承了Observable,又继承了Observer,因此既是观察者又是可观察者。您可以使用主题来订阅所有观察者,然后将主题订阅到后端数据源。
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-的更多信息扩展程序/RxJS/blob/master/doc/gettingstarted/subjects.md
评论
subscription.dispose()和subscription.unsubscribe()有什么区别?
–选择页-杰克·鲍(Jek Bao)
17年4月20日在8:19
@choopage没有区别。后者是新方法
–罗伊·纳米尔(Royi Namir)
17年4月25日在19:06
应该在处理主题之前取消订阅,否则,订阅将成为垃圾,因为它订阅了空值。
–张柔(Sophie Zhang)
18-10-11在14:28
#5 楼
我在示例中没有看到的一件事是,当您通过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);
#6 楼
可观察对象仅允许您订阅,而主题允许您同时发布和订阅。因此主题允许您将服务同时用作发布者和订阅者。
到目前为止,我对
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.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 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
:在app.component.ts
内,对Subject
进行订阅和取消订阅(以防止内存泄漏):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);
}
}
就这样。
现在,在
#message
的home.component.html
内部输入的任何值都应打印到{{message}}
内的app.component.html
评论
为什么要大形象?如果它与您的答案没有直接关系,则看起来像是诱饵。
–松饼
18-10-2在14:19
@ruffin这只是平均投票数的平均答案,请看我的个人资料。不一定是::D
–赞美·安萨里(Zameer Ansari)
18-10-3在11:01
较早前,我曾给您提供过赞成票,但您却回避了为什么会出现图像的问题。它与您的答案没有直接关系。不管您是否有很多代表,都没关系-如果该图像不是直接和明确的说明,我将要求您删除它。 /耸肩
–松饼
18-10-3在20:18
@ruffin如果它违反了社区的同意,那么它肯定不应该在那里!
–赞美·安萨里(Zameer Ansari)
18-10-6在6:16
#7 楼
app.component.ts behaviourService.setName("behaviour");
behaviour.service.ts
private name = new BehaviorSubject("");
getName = this.name.asObservable();`
constructor() {}
setName(data) {
this.name.next(data);
}
custom.component.ts
behaviourService.subscribe(response=>{
console.log(response); //output: behaviour
});
#8 楼
可以将Observables看作是其中有流动水的管道,有时水流动而有时却没有。在某些情况下,您实际上可能需要一个总是有水的管道,您可以通过创建一个特殊的管道来做到这一点,无论该管道有多小,该管道总是包含水,如果您碰巧是这样,可以称之为特殊管道BehaviorSubject。作为社区中的供水服务提供商,您可以在知道新安装的管道可以正常工作的情况下在晚上安然入睡。从技术上讲:您可能会遇到一些用例,在该用例中,可观察对象应始终具有价值,也许您想随时间捕获输入文本的值,然后可以创建BehaviorSubject实例来确保这种行为,例如:
const firstNameChanges = new BehaviorSubject("<empty>");
// pass value changes.
firstNameChanges.next("Jon");
firstNameChanges.next("Arya");
然后您可以使用“值”来采样随时间的变化。
firstNameChanges.value;
以后结合Observable时,这很方便,通过将流的类型视为BehaviorSubject,可以确保流至少触发一次或发出信号。
#9 楼
BehaviorSubject与Observable:RxJS具有观察者和可观察对象,Rxjs提供了多个用于数据流的类,其中一个是BehaviorSubject。Observables:Observables是随时间推移的多个值的惰性集合。 br />
BehaviorSubject:需要初始值并将其当前值发送给新订阅者的主题。
// 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
#10 楼
BehaviorSubjectBehaviorSubject建立在与ReplaySubject相同的功能之上,可以像主题一样热播并重播以前的值。
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');
Observables
开始,我们将研究创建常规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));
评论
我对常规主题的示例2有点困惑。为什么在您使用subject.next(“ b”)将值发送给主题的第二行上,订阅甚至无法获得任何结果?
– jmod999
16年11月11日在17:45
@ jmod999第二个示例是一个常规主题,该主题在调用订阅之前立即接收值。在常规主题中,仅针对调用后收到的值触发订阅。由于在订阅之前就已收到a,因此不会将其发送到订阅。
– Shantannu Bhadoria
17年4月19日在19:20
关于该奇妙解决方案的注释,如果在函数中使用它并返回它,则返回一个可观察的。我在返回主题时遇到了一些问题,这使其他只知道什么是Observable的开发人员感到困惑
–山姆
17年6月15日在13:41
我在星期三接受了Angular 4采访。由于我仍在学习新平台,因此他向我提出以下问题,例如“如果我订阅了一个尚未延迟加载的模块中的可观察对象,将会发生什么?”,这使我震惊。我不确定,但是他告诉我答案是使用BSubject-完全是Bhadoria先生在上面的解释。答案是使用BSubject,因为它总是返回最新值(至少这是我记得访问者对此的最终评论的方式)。
– bob.mazzo
17年11月24日15:48
@ bob.mazzo为什么在这种情况下需要使用BSubject? -如果我订阅该观察者,由于观察者尚未初始化,因此不会收到任何信息,因此它无法将数据推送给观察者;如果使用BSubject,由于相同的原因,我也不会获得任何信息。在这两种情况下,订户都不会收到任何东西,因为它位于尚未初始化的模块中。我对吗?
–拉斐尔·雷耶斯(Rafael Reyes)
18年6月13日在23:03