Subject vs Observable?


690

Açısal RxJ örüntülerine bakıyorum ve a BehaviorSubjectile an arasındaki farkı anlamıyorum Observable.

Anladığım kadarıyla, a BehaviorSubject, zaman içinde değişebilen bir değerdir (abone olabilir ve aboneler güncellenmiş sonuçlar alabilir). Bu bir ile aynı amaç gibi görünüyor Observable.

Bir Observablevs a ne zaman kullanılır BehaviorSubject? Bir kullanmanın faydası var mıdır BehaviorSubjectaşırı Observableya da tam tersi?

Yanıtlar:


970

BehaviorSubject bir tür öznedir, bir özne gözlemlenebilir özel bir türdür, böylece diğer gözlemlenebilir gibi iletilere abone olabilirsiniz. BehaviorSubject öğesinin benzersiz özellikleri şunlardır:

  • Bir başlangıç ​​değeri almalıdır, çünkü bir next()
  • Abonelik üzerine, konunun son değerini döndürür. Düzenli bir gözlemlenebilir, yalnızca bironnext
  • herhangi bir noktada, getValue()yöntemi kullanarak gözlemlenemeyen bir kodda konunun son değerini alabilirsiniz .

Bir öznenin gözlemlenebilir ile karşılaştırıldığında benzersiz özellikleri şunlardır:

  • Bu, gözlemlenebilir olmanın yanı sıra, bir konuya abone olmanın yanı sıra bir nesneye değerler de gönderebilirsiniz.

Buna ek olarak, asObservable()üzerindeki yöntemi kullanarak davranış konusundan bir gözlemlenebilir alabilirsiniz BehaviorSubject.

Gözlemlenebilir bir Geneldir ve BehaviorSubjectBehaviorSubject belirli niteliklere sahip bir gözlemlenebilir olduğu için teknik olarak bir Gözlemlenebilir alt türüdür.

BehaviorSubject ile örnek :

// 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

Normal konu ile Örnek 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

Bir gözlemlenebilir hem oluşturulabilir Subjectve BehaviorSubjectkullanma subject.asObservable().

Tek fark, gözlemlenebilir bir next()yöntem kullanarak değer gönderemezsiniz .

Açısal hizmetlerde, BehaviorSubjectbir veri hizmeti için, bileşen ve davranış konusu, bileşenin bu verilere aboneliğinden bu yana yeni güncellemeler olmasa bile, hizmeti tüketen bileşenin son güncellenen verileri almasını sağlamadan önce genellikle açılı bir hizmet olarak kullanacağım .


7
Normal konudaki örnek 2 ile biraz kafam karıştı. Abonelik neden konu.next ("b") kullanarak konuya değer gönderdiğiniz ikinci satırda bile bir şey almıyor?
jmod999

25
@ jmod999 İkinci örnek, abonelik çağrılmadan hemen önce bir değer alan normal bir konudur. Normal konularda abonelik yalnızca abonelik çağrıldıktan sonra alınan değerler için tetiklenir. A abonelikten hemen önce alındığı için aboneliğe gönderilmez.
Shantanu Bhadoria

Bu fantastik çözümle ilgili bir not, bunu bir işlevde kullanır ve geri verirseniz, gözlemlenebilir bir geri döndürür. Bir konuyu döndürmeyle ilgili bazı sorunlar yaşadım ve diğer gözlemcileri sadece Gözlenebilirlerin ne olduğunu bilen kafa karıştırıyor
sam

8
Çarşamba günü Açısal 4 röportajım oldu. Hala yeni platformu öğrendiğim için, bana "Henüz tembel olarak yüklenmemiş bir modülde bulunan bir gözlemlenebilirliğe abone olursam ne olur?" Emin değildim, ama cevabın BSubject - TAMAMEN Bay Bhadoria'nın yukarıda nasıl açıkladığını kullanmak olduğunu söyledi. Cevap bir BSubject kullanmaktı çünkü her zaman en son değeri döndürüyor (en azından görüşmecinin bu konudaki son yorumunu hatırlıyorum).
bob.mazzo

1
@ bob.mazzo Neden bu dava için bir BSubject kullanmam gerekiyor? - Eğer o Gözlemciye abone olursam, gözlemci başlatılmadığı için hiçbir şey alamayacağım çünkü gözlemcilere veri aktaramaz ve BSubject kullanırsam aynı nedenden dolayı hiçbir şey almayacağım. Her iki durumda da, abone başlatılmamış bir modül içerisindeyken abone hiçbir şey almaz. Haklı mıyım?
Rafael Reyes

183

Gözlemlenebilir: Her bir Gözlemci için farklı sonuç

Çok önemli bir fark. Gözlemlenebilir bir işlev olduğundan, herhangi bir durumu yoktur, bu nedenle her yeni Gözlemci için gözlemlenebilir oluşturma kodunu tekrar tekrar yürütür. Bunun sonucu:

Kod her gözlemci için çalıştırılır. Bir HTTP çağrısı ise, her gözlemci için çağrılır

Bu büyük hatalara ve verimsizliklere neden olur

BehaviorSubject (veya Subject) gözlemci ayrıntılarını depolar, kodu yalnızca bir kez çalıştırır ve sonucu tüm gözlemcilere verir.

Ör:

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>

Çıktı :

"observer 1: 0.7184075243594013"
"observer 2: 0.41271850211336103"
"observer subject 1: 0.8034263165479893"
"observer subject 2: 0.8034263165479893"

Kullanmanın Observable.createher gözlemci için nasıl farklı çıktı oluşturduğunu gözlemleyin, ancak BehaviorSubjecttüm gözlemciler için aynı çıktıyı verdi. Bu önemli.


Diğer farklılıklar özetlenmiştir.

┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃         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                          ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛

3
gelen herkes KnockoutJS's ko.observable()hemen Rx.BehaviorSubjectkarşılaştırıldığında daha fazla paralellik göreceksinizRx.Observable
Simon_Weaver

@Skeptor Gözlemlenebilir: abone olma yöntemi her zaman gözlemci ile ilişkili onNext yöntemini tetikler ve dönüş değerini getirir. BehaviourSubject / Subject: Akıştaki her zaman en son değeri döndürür. burada konu ile altyazı yöntemi, akıştaki en son değeri bulana kadar Observer'ın onNext yöntemini tetiklemez.
Mohan Ram

62

Gözlemlenebilir ve özne her ikisi de gözlemlenebilirdir, bir gözlemcinin onları izleyebileceği anlamına gelir. ama her ikisinin de kendine özgü özellikleri var. Ayrıca, her biri tekrar kendine özgü özelliklere sahip toplam 3 tip konu vardır. her birini anlamaya çalışalım.

pratik örneği burada stackblitz'de bulabilirsiniz . (Gerçek çıkışı görmek için konsolu kontrol etmeniz gerekir)

resim açıklamasını buraya girin

Observables

Bunlar soğuk: Kod, en az bir gözlemciye sahip olduklarında yürütülür.

Verilerin kopyasını oluşturur: Gözlenebilir, her bir gözlemci için verilerin bir kopyasını oluşturur.

Tek yönlü: Gözlemci gözlemlenebilir (orijin / ana) değer atayamaz.

Subject

Sıcaktırlar: kod yürütülmez ve gözlemci olmasa bile değer yayınlanır.

Verileri paylaşır: Aynı veriler tüm gözlemciler arasında paylaşılır.

iki yönlü: Gözlemci gözlemlenebilir (başlangıç ​​/ ana) değer atayabilir.

Subject kullanarak kullanıyorsanız, gözlemcinin oluşturulmasından önce yayınlanan tüm değerleri kaçırırsınız. İşte tekrar konu geliyor

ReplaySubject

Sıcaktırlar: kod yürütülmez ve gözlemci olmasa bile değer yayınlanır.

Verileri paylaşır: Aynı veriler tüm gözlemciler arasında paylaşılır.

iki yönlü: Gözlemci gözlemlenebilir (başlangıç ​​/ ana) değer atayabilir. artı

Mesaj akışını tekrar dinleme : Tekrarlama konusuna abone olursanız olun tüm yayınlanan mesajları alırsınız.

Konu ve tekrar oynatma konusunda başlangıç ​​değerini gözlemlenebilir olarak ayarlayamazsınız. İşte Davranışsal Konu geliyor

BehaviorSubject

Sıcaktırlar: kod yürütülmez ve gözlemci olmasa bile değer yayınlanır.

Verileri paylaşır: Aynı veriler tüm gözlemciler arasında paylaşılır.

iki yönlü: Gözlemci gözlemlenebilir (başlangıç ​​/ ana) değer atayabilir. artı

Mesaj akışını tekrar dinleme : Tekrarlama konusuna abone olursanız olun tüm yayınlanan mesajları alırsınız.

Başlangıç ​​değerini ayarlayabilirsiniz: Gözlenebilir olanı varsayılan değerle başlatabilirsiniz.


3
A'nın ReplaySubjectbir geçmişi olduğunu ve bir dizi (eski) değer yayınlayabildiğini / yayınlayabildiğini belirtmek gerekir . Sadece tampon 1 olarak ayarlandığında a BehaviorSubject.
Wilt

28

Gözlemlenebilir nesne, push tabanlı bir koleksiyonu temsil eder.

Gözlemci ve Gözlenebilir arabirimler, gözlemci tasarım deseni olarak da bilinen push tabanlı bildirim için genelleştirilmiş bir mekanizma sağlar. Gözlemlenebilir nesne, bildirim gönderen nesneyi (sağlayıcı) temsil eder; Observer nesnesi, onları alan sınıfı (gözlemci) temsil eder.

Konu sınıfı hem gözlemci hem de gözlemlenebilir olması bakımından hem Gözlenebilir hem de Gözlemci miras alır. Tüm gözlemcilere abone olmak için bir konuyu kullanabilir ve ardından konuyu arka uç veri kaynağına abone olabilirsiniz

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 hakkında daha fazla bilgi


Subscription.dispose () ve Subscription.unsubscribe () arasındaki fark nedir?
choopage - Jek Bao

4
@ choopage fark yok. İkincisi yeni bir yoldur
Royi Namir

Özne elden çıkarılmadan önce abonelikten çıkılırsa, abonelik bir boş değere abone olduğu için çöp haline gelir.
Sophie Zhang

20

Örneklerde göremediğim bir şey, BehaviorSubject öğesini asObservable aracılığıyla Observable'a koyduğunuzda, abonelikte son değeri döndürme davranışını devralmasıdır.

Bu zor bir bit, genellikle kütüphaneler alanları gözlemlenebilir olarak gösterecektir (yani Angular2'deki ActivatedRoute içindeki parametreler), ancak sahnelerin arkasında Subject veya BehaviorSubject kullanabilir. Kullandıkları şey abone olma davranışını etkileyecektir.

Buraya bakın 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);

11

Bir gözlemlenebilir bir oysa sadece abone olmalarını sağlar konu hem yayınlamak ve abone olmanızı sağlar.

Böylece konu, hizmetlerinizin hem yayıncı hem de abone olarak kullanılmasına izin verir .

Şu an itibariyle o kadar iyi değilim, Observablebu yüzden sadece bir örneğini paylaşacağım Subject.

Açısal bir CLI örneğiyle daha iyi anlayalım . Aşağıdaki komutları çalıştırın:

npm install -g @angular/cli

ng new angular2-subject

cd angular2-subject

ng serve

İçeriğini değiştir app.component.html:

<div *ngIf="message">
  {{message}}
</div>

<app-home>
</app-home>

ng g c components/homeAna bileşeni oluşturmak için komutu çalıştırın . İçeriğini değiştir home.component.html:

<input type="text" placeholder="Enter message" #message>
<button type="button" (click)="setMessage(message)" >Send message</button>

#messageburada yerel değişkendir. Adlı message: string; kişinin app.component.tssınıfına bir özellik ekleyin .

Bu komutu çalıştırın ng g s service/message. Bu, adresinde bir hizmet oluşturur src\app\service\message.service.ts. Bu hizmeti uygulamaya sağlayın .

İthalat Subjectiçine MessageService. Bir konu da ekleyin. Son kod şöyle görünecektir:

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
  }
}

Şimdi, bu hizmeti enjekte edin home.component.tsve bir örneğini yapıcıya iletin . Bunu app.component.tsda yapın. Değerini #messagehizmet işlevine iletmek için bu hizmet örneğini kullanın 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);
  }
}

İçeride app.component.tsabone olun ve abonelikten çıkın (bellek sızıntılarını önlemek için) 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();
  }
}

Bu kadar.

Şimdi, herhangi bir değer içeriye girdi #messageait home.component.htmlyazdırılabilir edilecektir {{message}}app.component.html


Neden dev görüntü? Eğer doğrudan cevabınızla ilgili değilse, votebait gibi görünüyor.
ruffin

@ruffin Bu, ortalama oy sayısı ile ortalama bir cevap, profilime bakın. Kesinlikle oylama değil: D
Muhammed

1
Sana daha önce bir oy verdim, ama resmin neden orada olduğu sorusunu atladın. Doğrudan cevabınızla ilgili değil. Çok sayıda temsilciniz olup olmadığı önemli değil - eğer görüntü doğrudan ve özellikle açıklayıcı değilse, kaldırmanızı rica ediyorum . shrug
ruffin

1
@ruffin Toplumun rızasına aykırı olursa, kesinlikle orada olmamalıdır!
Mohammed Zameer

4

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

1

BehaviorSubject vs Observable : RxJS'nin gözlemcileri ve gözlemlenebilir özellikleri vardır, Rxjs veri akışlarıyla kullanmak için birden fazla sınıf sunar ve bunlardan biri bir BehaviorSubject.

Gözlemlenebilirler : Gözlenebilirler, zaman içinde birden çok değerin tembel koleksiyonlarıdır.

BehaviorSubject : Başlangıç ​​değeri gerektiren ve geçerli değerini yeni abonelere yayan Konu.

 // 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

1

Gözlemlenebilirleri içinde akan su olan bir boru olarak düşünün , bazen su akar ve bazen de akmaz. Bazı durumlarda, içinde her zaman su olan bir boruya ihtiyacınız olabilir, bunu ne kadar küçük olursa olsun, her zaman su içeren özel bir boru oluşturarak yapabilirsiniz , eğer bu özel boru BehaviorSubject diyelim. Topluluğunuzdaki bir su kaynağı sağlayıcısı, yeni kurulan borunuzun sadece çalıştığını bilerek geceleri huzur içinde uyuyabilirsiniz.

Teknik terimlerle: bir Gözlemlenebilir öğenin her zaman değeri olması gereken kullanım senaryolarıyla karşılaşabilirsiniz, belki de bir giriş metninin zaman içindeki değerini yakalamak istiyorsanız, daha sonra bu tür bir davranış sağlamak için BehaviorSubject örneğini oluşturabilirsiniz, diyelim:


const firstNameChanges = new BehaviorSubject("<empty>");

// pass value changes.
firstNameChanges.next("Jon");
firstNameChanges.next("Arya");

Daha sonra zaman içindeki değişiklikleri örneklemek için "değer" kullanabilirsiniz.


firstNameChanges.value;

Bu, Gözlemlenebilirleri daha sonra birleştirdiğinizde, akışınızın türüne BehaviorSubject olarak göz atarak, akışın en azından en az bir kez tetiklenmesini veya sinyal vermesini sağlayabilirsiniz .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.