BehaviorSubject vs Observable?

守給你的承諾、 提交于 2020-02-27 22:54:55

我正在研究Angular RxJs模式,我不明白BehaviorSubjectObservable之间的区别。

根据我的理解, BehaviorSubject是一个可以随时间变化的值(可以订阅,订阅者可以接收更新的结果)。 这似乎是Observable的完全相同的目的。

你什么时候使用ObservableBehaviorSubject ? 在Observable上使用BehaviorSubject是否有好处,反之亦然?


#1楼

Observable对象表示基于推送的集合。

Observer和Observable接口为基于推送的通知提供了一种通用机制,也称为观察者设计模式。 Observable对象表示发送通知的对象(提供者); Observer对象表示接收它们的类(观察者)。

Subject类继承Observable和Observer,因为它既是观察者又是observable。 您可以使用主题订阅所有观察者,然后将主题订阅到后端数据源

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的更多信息


#2楼

BehaviorSubject是一种主题,主题是一种特殊类型的可观察对象,因此您可以像任何其他可观察对象一样订阅消息。 BehaviorSubject的独特功能是:

  • 它需要一个初始值,因为它必须始终返回订阅值,即使它没有收到next()
  • 订阅后,它将返回主题的最后一个值。 常规observable仅在收到onnext时触发
  • 在任何时候,您都可以使用getValue()方法在不可观察的代码中检索主题的最后一个值。

与可观察对象相比,主题的独特特征是:

  • 除了作为一个可观察者之外,它还是一个观察者,因此除了订阅它之外,您还可以向主题发送值。

此外,您可以使用BehaviorSubject上的asObservable()方法从行为主题中获取可观察对象。

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()SubjectBehaviorSubject创建一个observable。

唯一的区别是您无法使用next()方法将值发送到observable。

在Angular服务中,我将使用BehaviorSubject作为数据服务,因为角度服务通常在组件和行为主体之前初始化,即使自组件订阅此数据以来没有新的更新,消费服务的组件也会接收上次更新的数据。


#3楼

可观察:每个观察者的结果不同

一个非常重要的区别。 由于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                          │
└─────────────────────────────────────┴─────────────────────────────────────┘

#4楼

我在示例中没有看到的一件事是,当您通过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);

#5楼

可观察 对象允许您仅订阅,而主题允许您同时发布和订阅。

因此,主题允许您的服务既可以用作发布者,也可以用作订阅者。

截至目前,我不太擅长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();
  }
}

而已。

现在,内部输入的任何值#messagehome.component.html须印到{{message}}内部app.component.html

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!