簡體   English   中英

rxjs 中的 Observable 和 Subject 有什么區別?

[英]What is the difference between Observable and a Subject in rxjs?

我正在瀏覽這個博客並閱讀有關 Observables 的內容,但無法弄清楚 Observable 和 Subject 之間的區別。

在流編程中有兩個主要接口: ObservableObserver

Observable是針對消費者的,它可以被轉化和訂閱:

observable.map(x => ...).filter(x => ...).subscribe(x => ...)

Observer是用於提供可觀察源的接口:

observer.next(newItem)

我們可以使用Observer創建新的Observable

var observable = Observable.create(observer => { 
    observer.next('first'); 
    observer.next('second'); 
    ... 
});
observable.map(x => ...).filter(x => ...).subscribe(x => ...)

或者,我們可以使用同時實現ObservableObserver接口的Subject

var source = new Subject();
source.map(x => ...).filter(x => ...).subscribe(x => ...)
source.next('first')
source.next('second')

Observable 設計為單播,Subjects 設計為多播。

如果您查看下面的示例 -每個訂閱都會收到不同的值作為設計為單播開發的 observable。

import {Observable} from 'rxjs';

let obs = Observable.create(observer=>{
   observer.next(Math.random());
})

obs.subscribe(res=>{
  console.log('subscription a :', res); //subscription a :0.2859800202682865
});

obs.subscribe(res=>{
  console.log('subscription b :', res); //subscription b :0.694302021731573
});

如果您期望訂閱的值相同,這可能會很奇怪。

我們可以使用 Subjects 來解決這個問題。 主題類似於事件發射器,它不會為每個訂閱調用。 考慮下面的例子。

import {Subject} from 'rxjs';

let obs = new Subject();

obs.subscribe(res=>{
  console.log('subscription a :', res); // subscription a : 0.91767565496093
});

obs.subscribe(res=>{
  console.log('subscription b :', res);// subscription b : 0.91767565496093
});

obs.next(Math.random());

兩個訂閱都獲得了相同的輸出值!。

可觀察對象

  1. 他們很冷漠:當他們至少有一個觀察者時,代碼就會被執行。

  2. 創建數據副本:Observable 為每個觀察者創建數據副本。

  3. 單向:Observer 不能為 observable(origin/master)賦值。

  4. 代碼將為每個觀察者運行。 如果是 HTTP 調用,則每個觀察者都會調用它。

  5. 如果它是我們想要在所有組件之間共享的服務,它不會有最新結果所有新訂閱者仍將訂閱相同的 observable 並從頭開始獲取價值

  6. 單播意味着可以從 observable 發出值,而不是從任何其他組件發出值。

主題

  1. 它們很熱:即使沒有觀察者,代碼也會被執行並且值會被廣播。

  2. 共享數據:在所有觀察者之間共享相同的數據。

  3. 雙向:Observer 可以為 observable(origin/master) 賦值。

  4. 如果使用 using 主題,那么您將錯過在創建觀察者之前廣播的所有值。 所以這里來了重播主題

  5. 多播,可以將值投射到多個訂閱者,並且可以同時充當訂閱者和發射者

請參閱 rxjs 文檔(更多信息和示例): http ://reactivex.io/rxjs/manual/overview.html#subject

什么是主題? RxJS Subject 是一種特殊類型的 Observable,它允許將值多播到許多觀察者。 雖然普通的 Observable 是單播的(每個訂閱的 Observer 擁有一個獨立的 Observable 執行),但主題是多播的。

一個 Subject 就像一個 Observable,但可以多播給許多觀察者。 主題就像 EventEmitters:它們維護着許多偵聽器的注冊表。

和代碼,擴展Observable Subjecthttps : //github.com/ReactiveX/rxjs/blob/master/src/internal/Subject.ts#L22

/**
 * @class Subject<T>
 */
export class Subject<T> extends Observable<T> implements SubscriptionLike {
//...
}

Observable 只能通知一個觀察者,而 Subject 可以通知多個觀察者。

我發現接受的答案有點令人困惑!

Observer不是用於提供Observable源的接口,而是用於觀察Observable源的接口……從名稱上看更有意義,對嗎?

所以,原因是:

var observable = Observable.create(observer => { 
    observer.next('first'); 
    observer.next('second'); 
    ... 
});

工作 - 創建一個發出“第一個”然后“第二個”的可觀察對象 - Observable.create(...)的參數是一個訂閱函數,它基本上定義了哪些Observer事件將在該Observable的直接Observer上發生。

如果你想再深入一點,重要的是要理解訂閱函數在你訂閱時不是直接在Observer對象上調用的,而是由一個Subscription對象中介,它可以強制執行正確的可觀察規則,例如Observable永遠不會在調用了observer.complete()之后發出新值,即使您的 subscribe 函數看起來好像是這樣。

參考: http : //reactivex.io/rxjs/manual/overview.html#creating-observables

一個Subject既是一個Observable又是一個觀察者,再一次,它看起來就像Observer接口是將事件“饋送”給Subject 的方式 但是,如果您意識到Subject有點像Observable並具有與 subscribe 功能等效的Observable (即,您定義觀察它的事物將發生什么事件),則命名更容易理解,即使在它之后,它也位於對象上已經被創造了。 因此,您在Subject上調用Observer方法來定義觀察它的事物將發生什么Observer事件! 😊(同樣,涉及中間對象,以確保您只能做合法的事情序列。)

參考: http : //reactivex.io/rxjs/manual/overview.html#subject

從另一個角度來看,注意到訂閱一個 Observable 會重新執行 Observable 函數是好的。 例如,如果數據源是服務,這可能會導致性能問題。

如果您希望多個訂閱者獲得相同的值,您可能需要一個 Subject 為此,請確保在主題訂閱數據源之前設置您的訂閱。 否則,您的過程將被卡住。

更多細節在這里: https : //javascript.tutorialhorizo​​n.com/2017/03/23/rxjs-subject-vs-observable/

想象一下,如果您有一個數據流進入您的應用程序,就像在 websocket 連接中一樣。 你想要一種方法來處理它。 有幾個解決辦法:

1.普通ajax請求:這個方案不可行,因為不適用於處理推送數據。 與其說是推,不如說是拉。

2. Promise:也不好,因為你必須觸發它們並且它們只能檢索一次。 也更多的是拉然后推。

所以為了取回這個數據,在過去,我們做一個長輪詢。 例如,我們在這里設置了一個間隔函數來每 1 分鍾檢索一次該數據流。 雖然它有效,但它實際上加重了 CPU 和內存等資源的負擔。

但現在有了選項 3,

3. Observable:你可以訂閱並讓數據流不停地進來,直到函數完成被調用。

酷吧? 但是還有另一個問題。 如果您只想在應用程序中的某處觀察一次傳入數據,該怎么辦? 但是您希望在數據到達時在您的應用程序周圍同時使用該數據。 那是您何時何地使用主題。 您將 subject.subscribe() 放在您希望在整個應用程序中使用的地方。 當數據到達時,有subject.subscribe() 的地方會同時處理它們。 但是觀察者必須像這樣訂閱主題作為其參數。

觀察者.訂閱(主題)。

示例應用程序是當您想要構建通知警報時。

您不能對同一個 observable 進行多個訂閱,因為很有可能每個訂閱者都會收到不同的輸入數據。 但是對於主題,所有通過主題 subscribe() 的操作都將檢索相同的數據。

另一個類比是通過雜志訂閱。 每個訂閱者都會收到帶有他們名字的雜志。 所以,不同的訂閱 = 不同的接收者姓名。(Normal Observable)但是當你與你的朋友分享時,你所有的朋友都會收到同樣的雜志,上面只有你的名字。(Normal Observable with Subject)

這家伙用代碼示例很好地解釋了它。 您可以在https://javascript.tutorialhorizo​​n.com/2017/03/23/rxjs-subject-vs-observable/查看

希望這個答案有幫助。

Observable :只有 Observable 知道如何以及何時在 observable 上觸發事件。 next()方法只能在實例化的構造函數中調用。 此外,每次訂閱時,都會創建一個單獨的觀察者,並僅在構造函數內部使用特定的觀察者調用next()方法,在以下示例中, subscriber本身就是觀察者,並且在實例化的構造函數執行時訂閱它。 前任:

import { Observable } from 'rxjs';

const observable = new Observable(subscriber => {
  subscriber.next(1);
  subscriber.next(2);
  setTimeout(() => {
    subscriber.next(3);        
  }, 1000);
});

Subject :這里的next()方法可以在構造函數之外的任何地方被主題使用。 此外,在訂閱之前調用next()方法時,將錯過特定事件。 因此,只有在訂閱后才必須調用next()方法。 前任:

import { Subject } from 'rxjs';
 
const subject = new Subject<number>();
 

subject.next(1); // this is missed
subject.subscribe({
  next: (v) => console.log(`observerA: ${v}`)
});
subject.subscribe({
  next: (v) => console.log(`observerB: ${v}`)
});     
subject.next(2);

簡要地,

主題:您可以發送到它並從中接收

觀察到的:你可以從它只能接收

換句話說,在主題中你可以訂閱你可以使用它隨時隨地在代碼中廣播給其他訂閱者。

同時,在觀察到只能訂閱(它初始化之后,你不能用它來廣播數據)。 唯一可以從 observable 廣播數據的地方是它的構造函數內部。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM