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

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

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


当前回答

可观察对象和主体都是可观察对象,这意味着观察者可以跟踪它们。它们都有一些独特的特点。有三种类型的科目,每一种也有独特的特点。

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

观察

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

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

单向:观察者不能给观察对象赋值(源/主)。

主题

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

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

双向:观察者可以给观察对象赋值(源/主)。

如果你正在使用subject,那么你会错过所有在创建观察者之前传播的值。这就是重放主题

ReplaySubject

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

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

双向:观察者可以给观察对象赋值(源/主)。+

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

在Subject和ReplaySubject中,不能将初始值设置为observable。这就是行为主体…

BehaviorSubject

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

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

双向:观察者可以给观察对象赋值(源/主)。+

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

你可以设置初始值:你可以用默认值初始化可观察对象。

其他回答

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

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

你也可以像这样将一个主题更改为一个可观察对象:

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

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

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

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

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

在rxjs中,Subject本质上是一个观察者和可观察对象。观察者是我们放入值的对象,可观察对象是我们可以观察值的对象。

Subject is Hot by default. Observables by default are cold. That means they are not going to emit any values until someone subscribes to it. The instant we create a subject, we can emit a value from it and that value will be emitted even if nobody is subscribed to it yet. Subject is multicast by default. Observable by default are unicast and that means that for every different observer that we have, we have to subscibe to an observable, if that observable emits a value that value is going to flow through all the different operators inside of our pipe once for each subscriber. Multicast means all of other operators will run one time for every value, regardless of the number of observers we have. GOTCHA= thE SUBJECT is multicast but if you chain on a pipe statement to it, that is going to return a new observable that is cold and unicast.

行为主体与主体相同,但也有初始的“种子”值。新订阅用户立即获得最新的值。如果有人订阅了行为主体,它会立即接收到最近的值。所以行为主体总有一些价值可以分给订阅者。

关于行为主体最有用的事情是当我们开始发出网络请求时。想象一下,我们将一些管道连接到一个行为主题上,在一个管道函数或管道操作符中,我们最终发出一个网络请求并获取一些数据。你最终可能会想让其他东西订阅那个可观察对象,并立即获得已经获取的数据。使用行为主体,我们可以很容易地实现这种行为。