BehaviorSubject vs Observable?

我正在研究Angular RxJs模式,我不明白BehaviorSubjectObservable之間的區別。 css

根據個人理解, BehaviorSubject是一個能夠隨時間變化的值(能夠訂閱,訂閱者能夠接收更新的結果)。 這彷佛是Observable的徹底相同的目的。 html

你何時使用ObservableBehaviorSubject ? 在Observable上使用BehaviorSubject是否有好處,反之亦然? git


#1樓

Observable對象表示基於推送的集合。 github

Observer和Observable接口爲基於推送的通知提供了一種通用機制,也稱爲觀察者設計模式。 Observable對象表示發送通知的對象(提供者); Observer對象表示接收它們的類(觀察者)。 ajax

Subject類繼承Observable和Observer,由於它既是觀察者又是observable。 您可使用主題訂閱全部觀察者,而後將主題訂閱到後端數據源 npm

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()方法在不可觀察的代碼中檢索主題的最後一個值。

與可觀察對象相比,主題的獨特特徵是: angular2

  • 除了做爲一個可觀察者以外,它仍是一個觀察者,所以除了訂閱它以外,您還能夠向主題發送值。

此外,您可使用BehaviorSubject上的asObservable()方法從行爲主題中獲取可觀察對象。 app

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

相關文章
相關標籤/搜索