ChatGPT解决这个技术问题 Extra ChatGPT

BehaviorSubject vs Observable?

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

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

您什么时候使用 ObservableBehaviorSubject?使用 BehaviorSubject 而不是 Observable 是否有好处,反之亦然?

这篇文章特别帮助我以 ELI5 方式理解 observables vs subject vs behavior subject javascript.plainenglish.io/…

y
yivi

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

它需要一个初始值,因为它必须始终在订阅时返回一个值,即使它没有收到 next()

订阅后,它返回主题的最后一个值。常规的 observable 仅在收到 onnext 时触发

在任何时候,您都可以使用 getValue() 方法在不可观察的代码中检索主题的最后一个值。

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

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

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

Observable 是 Generic,而 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 won't get 
                                          // anything at this point
});

subject.next("c"); // Subscription got c
subject.next("d"); // Subscription got d

可以使用 subject.asObservable()SubjectBehaviorSubject 创建 observable。

唯一的区别是您不能使用 next() 方法将值发送到可观察对象。

在 Angular 服务中,我会将 BehaviorSubject 用于数据服务,因为 Angular 服务通常在组件之前初始化,并且行为主体确保使用该服务的组件接收到最后更新的数据,即使自组件订阅后没有新的更新也是如此数据。


我对常规主题的示例 2 有点困惑。为什么即使在第二行您使用subject.next(“b”)向主题发送值,订阅也不会得到任何东西?
@jmod999 第二个示例是一个常规主题,它在调用订阅之前接收一个值。在常规主题中,只有在调用订阅后收到的值才会触发订阅。由于 a 是在订阅之前收到的,因此它不会发送到订阅。
周三我接受了 Angular 4 的面试。由于我还在学习新平台,他问我诸如“如果我订阅一个尚未延迟加载的模块中的可观察对象会发生什么?我不确定,但他告诉我答案是使用 BSubject - 正是 Bhadoria 先生在上面解释的。答案是使用 BSubject,因为它总是返回最新的值(至少我记得面试官对此的最终评论)。
@bob.mazzo 为什么我需要在这种情况下使用 BSubject? -- 如果我订阅了那个观察者,我不会收到任何东西,因为观察者没有被初始化,所以它不能将数据推送给观察者,如果我使用 BSubject,我也不会收到任何东西,因为同样的原因。在这两种情况下,订阅者都不会收到任何东西,因为它位于尚未初始化的模块中。我对吗?
服务不应该有私有 BehaviourSubject 并且值是从发出 BehaviourSubject 值的公共 Observable 访问的,因此不允许在服务外部的 BS 上调用 next ?
M
M. Al Jumaily

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

一个非常非常重要的区别。由于 Observable 只是一个函数,它没有任何状态,所以对于每一个新的 Observer,它都会一次又一次地执行 observable 创建代码。这导致:

代码为每个观察者运行。如果它是一个 HTTP 调用,它会被每个观察者调用

这会导致重大错误和效率低下

BehaviorSubject (或 Subject )存储观察者详细信息,只运行一次代码并将结果提供给所有观察者。

前任:

JSBin:http://jsbin.com/qowulet/edit?js,console

// --- Observable --- 让 randomNumGenerator1 = Rx.Observable.create(observer => { observer.next(Math.random()); });让observer1 = randomNumGenerator1 .subscribe(num => console.log('observer 1: '+ num));让observer2 = randomNumGenerator1 .subscribe(num => console.log('observer 2: '+ num)); // ------ BehaviorSubject/ Subject let randomNumGenerator2 = new Rx.BehaviorSubject(0); randomNumGenerator2.next(Math.random()); letobserver1Subject = randomNumGenerator2 .subscribe(num=> console.log('observer subject 1: '+ num)); letobserver2Subject = randomNumGenerator2 .subscribe(num=> console.log('observer subject 2: '+ num));

输出 :

"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's ko.observable() 的任何人都会立即看到与 Rx.BehaviorSubject 的更多相似之处
@Skeptor Observable:subscribe 方法会一直触发与观察者关联的 onNext 方法并带来返回值。 BehaviourSubject/Subject:将始终返回流中的最新值。这里的 subcribe 方法不会触发其 Observer 的 onNext 方法,直到它在流中找到最新的值。
C
Community

Observable 和 Subject 都是 observable 的,这意味着观察者可以跟踪它们。不过,它们都有一些独特的特征。此外,还有 3 种类型的主题,每一种都具有独特的特点。

您可以在 stackblitz 上找到实际示例。 (您需要检查控制台才能看到实际输出)

https://i.stack.imgur.com/oLsZ4.png

Observables

他们很冷:当他们至少有一个观察者时,代码就会被执行。

创建数据副本:Observable 为每个观察者创建数据副本。

单向:Observer 不能为 observable(origin/master) 赋值。

Subject

它们很热:即使没有观察者,代码也会被执行并且值会被广播。

共享数据:所有观察者之间共享相同的数据。

双向:Observer 可以为 observable(origin/master) 赋值。

如果正在使用主题,那么您会错过在创建观察者之前广播的所有值。所以来了重播主题

ReplaySubject

它们很热:即使没有观察者,代码也会被执行并且值会被广播。

共享数据:所有观察者之间共享相同的数据。

双向:Observer 可以为 observable(origin/master) 赋值。加

重播消息流:无论您何时订阅重播主题,您都会收到所有广播的消息。

在 Subject 和 ReplaySubject 中,不能将初始值设置为 observable。所以这里出现了 BehavioralSubject...

BehaviorSubject

它们很热:即使没有观察者,代码也会被执行并且值会被广播。

共享数据:所有观察者之间共享相同的数据。

双向:Observer 可以为 observable(origin/master) 赋值。加

重播消息流:无论您何时订阅重播主题,您都会收到所有广播的消息。

您可以设置初始值:您可以使用默认值初始化 observable。


值得一提的是,ReplaySubject 具有历史记录并且可以广播/发出一系列(旧)值。只有当缓冲区设置为 1 时,它的行为类似于 BehaviorSubject
对于 BehaviorSubject 段落“重播消息流”似乎不正确
M
Md Ayub Ali Sarker

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-Extensions/RxJS/blob/master/doc/gettingstarted/subjects.md


subscription.dispose() 和 subscription.unsubscribe() 有什么区别?
@choopage 没有区别。后者是新的方式
应该在主题被释放之前取消订阅,否则订阅会变成垃圾,因为它订阅了一个空值。
L
Lukasz Marek Sielski

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

x
xameeramir

observable 只允许您订阅,而 subject 允许您发布和订阅。

因此,主题允许您的 services 同时用作发布者和订阅者。

到目前为止,我还不太擅长 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 处生成服务。提供this service to the app

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}}


为什么是巨像?如果它与您的答案没有直接关系,那么它似乎是投票诱饵。
@ruffin 这只是平均票数的平均答案,请查看我的个人资料。不一定是投票诱饵:D
我之前给了你一个赞成票,但你回避了为什么图像在那里的问题。它与您的答案没有直接关系。不管你是否有很多代表——if the image isn't directly and specifically elucidatory, I'd request you remove it。 /耸耸肩
@ruffin 如果它违反了社区的同意,那么它肯定不应该存在!
R
Ronnel Reposo

将 Observables 想象成一个管道,里面有流动的水,有时水会流动,有时不会。在某些情况下,您实际上可能需要一个始终有水的管道,您可以通过创建一个始终包含水的特殊管道来做到这一点,无论它有多小,如果您碰巧是,我们将此特殊管道称为 BehaviorSubject作为您社区的供水供应商,您知道新安装的管道正常工作,您可以在晚上安然入睡。

用技术术语来说:您可能会遇到 Observable 应该始终具有价值的用例,也许您想随着时间的推移捕获输入文本的值,然后您可以创建 BehaviorSubject 的实例来确保这种行为,让我们说:


const firstNameChanges = new BehaviorSubject("<empty>");

// pass value changes.
firstNameChanges.next("Jon");
firstNameChanges.next("Arya");

然后,您可以使用“值”对随时间的变化进行采样。


firstNameChanges.value;

当您稍后组合 Observables 时,这会很方便,通过查看流的类型为 BehaviorSubject,您可以确保流至少触发或至少发出一次信号。


涵盖了很多部分,但你解释的好处是给出了一个易于理解的类比,工藤!!!
v
vineet

app.component.ts

behaviourService.setName("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
});

F
Flash

BehaviorSubject vs Observable:RxJS 有观察者和可观察者,Rxjs 提供了多个用于数据流的类,其中之一是 BehaviorSubject。

Observables:Observables 是多个值随时间推移的惰性集合。

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

N
Naeem Bashir

Observable 是一个泛型,

Observables 是多个值随时间推移的惰性集合。

只是一个函数,没有状态

为每个观察者运行代码

BehaviorSubject:需要初始值并将其当前值发送给新订阅者的主题。

从技术上讲,它是 Observable 的子类型,因为 BehaviorSubject 是具有特定品质的可观察对象。

有状态。将数据存储在内存中

相同的代码对所有观察者只运行一次

BehaviorSubject 的独特之处如下:

它需要一个初始值,因为它必须始终在订阅时返回一个值,即使它没有收到 next()

订阅后,它返回主题的最后一个值。常规的 observable 仅在收到 onnext 时触发

在任何时候,您都可以使用 getValue() 方法在不可观察的代码中检索主题的最后一个值。


Y
Yilmaz

rxjs 中的主题本质上是一个观察者和可观察者的混合体。 Observer 是我们投入值的东西,observable 是我们可以观察值的东西。

主题默认为热门。 Observables 默认是冷的。这意味着他们不会发出任何值,直到有人订阅它。在我们创建一个主题的那一刻,我们可以从中发出一个值,即使没有人订阅它,该值也会被发出。

主题默认为多播。默认情况下,Observable 是单播的,这意味着对于我们拥有的每个不同的观察者,我们必须订阅一个 observable,如果该 observable 发出一个值,该值将为每个订阅者流过管道内的所有不同运算符一次.多播意味着所有其他运算符将为每个值运行一次,无论我们拥有多少观察者。

GOTCHA= THE SUBJECT 是多播的,但是如果您将管道语句链接到它,那将返回一个新的冷单播的 observable。

行为主体与主体相同,但也采用初始“种子”值。新订户立即获得最新价值。如果有人订阅了 Behavior 主题,它将立即收到最新的值。因此,行为主题总是有一些价值可以提供给订阅者。

行为主体最有用的事情是当我们开始发出网络请求时。想象一下,我们将一些管道内容链接到行为主体,并在管道函数或管道运算符内部,我们最终发出网络请求并获取一些数据。您最终可能希望让其他东西订阅该 observable 并立即获取已经获取的数据。使用行为主体,我们可以轻松实现这种行为。


Y
Yogesh Waghmare

行为主体

BehaviorSubject 建立在与我们的 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');

可观察的

首先,我们将查看创建常规 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));

b
brainoverflow98

我认为 Observable 作为主题的包装。而 Observable 仅用于订阅数据更改。 Subject 也可以用来通知订阅者数据的变化(使用 next() 方法)。这是一个小的可观察模式实现,可以帮助您理解这个概念。 TypeScript Playground


J
Juliano Soder

为了清楚起见,您还可以将主题更改为这样的可观察对象:

 page = new BehaviorSubject<String|null>(null);
 actualPage:Observable<string> = new Observable()

this.page.next("hardware")
this.actualPage = this.page as Observable<any>;

关注公众号,不定期副业成功案例分享
关注公众号

不定期副业成功案例分享

领先一步获取最新的外包任务吗?

立即订阅