首页 文章

BehaviorSubject vs Observable?

提问于
浏览
408

我'm looking into Angular RxJs patterns and I don' t了解 BehaviorSubjectObservable 之间的区别 .

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

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

7 回答

  • 0

    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
    });
    
  • 103

    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 内输入的任何值都应打印到 {{message}} app.component.html

  • 3

    Observablesubject 都是可观察的,意味着观察者可以跟踪它们 . 但它们都有一些独特的特征 . 此外,总共有3种类型的受试者,每种受试者都具有独特的特征 . 让我们试着去了解每一个 .

    你可以在stackblitz找到实际的例子 . (You need to check the console to see the actual output)

    enter image description here

    Observables

    They are cold: 代码在具有单个观察者的列表中执行 .

    Creates copy of data: Observable为每个观察者创建数据副本 .

    Uni-directional: Observer无法将值赋给observable(origin / master) .

    Subject

    即使没有观察者, They are hot: 代码也会被执行并且值被广播 .

    Shares data: 所有观察者之间共享相同的数据 .

    bi-directional: Observer可以将值赋给observable(origin / master) .

    如果正在使用主题,那么您将错过创建观察者之前所有的值 . 所以来了 Replay Subject

    Replay Subject

    即使没有观察者, They are hot: 代码也会被执行并且值被广播 .

    Shares data: 所有观察者之间共享相同的数据 .

    bi-directional: Observer可以将值赋给observable(origin / master) . 加

    Replay the message stream: 无论您何时订阅重播主题,您都将收到所有的brodcasted消息 .

    在主题和重放主题中,您无法将初始值设置为可观察 . 所以来了 Behavioral Subject

    Behavioral Subject

    即使没有观察者, They are hot: 代码也会被执行并且值被广播 .

    Shares data: 所有观察者之间共享相同的数据 .

    bi-directional: Observer可以将值赋给observable(origin / master) . 加

    Replay the message stream: 无论您何时订阅重播主题,您都将收到所有brodcasted消息 .

    You can set initial value: 您可以使用默认值初始化observable .

  • 7

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

    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

  • 13

    Observable:每个Observer的结果不同

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

    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 用于数据服务,因为角度服务通常在组件和行为主体之前初始化,即使自组件订阅此数据以来没有新的更新,消费服务的组件也会接收最后更新的数据 .

相关问题