我正在研究Angular RxJs模式,我不明白行为主体和可观察对象之间的区别。

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

什么时候使用可观察对象和行为主体?使用一个行为主体比使用一个可观察对象有好处吗?反之亦然?


当前回答

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

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

到目前为止,我不太擅长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}}

其他回答

BehaviorSubject

BehaviorSubject构建在与我们的ReplaySubject相同的功能之上,比如,hot,并重放先前的值。

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));

我认为可观察对象是主体的包装。而Observable仅用于订阅数据更改。Subject还可以用于将数据更改通知订阅者(使用next()方法)。下面是一个小的可观察的模式实现,它可能有助于您理解这个概念。打印稿操场

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

BehaviorSubject是一种类型的主题,主题是一种特殊类型的可观察对象,所以你可以像其他可观察对象一样订阅消息。行为主体的独特之处在于:

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

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

它是一个观察者,除了是一个可观察对象,所以你也可以发送值到一个主题,除了订阅它。

此外,你可以使用行为主体上的asObservable()方法从行为主体获取一个可观察对象。

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()从Subject和BehaviorSubject创建一个可观察对象。

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

在Angular服务中,我会为数据服务使用BehaviorSubject,因为Angular服务通常会在组件之前进行初始化,而behavior subject会确保使用该服务的组件接收到最后一次更新的数据,即使自该组件订阅该数据以来没有新的更新。

行为主体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