BehaviorSubject와 Observable?


690

나는 각도 RxJs 패턴으로 찾고 있어요와 나는 사이의 차이 이해하지 못하는 BehaviorSubject와를 Observable.

내 이해에서, a BehaviorSubject는 시간이 지남에 따라 변경 될 수있는 값입니다 (구독 할 수 있으며 구독자는 업데이트 된 결과를받을 수 있음). 이것은의 동일한 목적으로 보인다 Observable.

언제 Observablevs 를 사용 BehaviorSubject하시겠습니까? BehaviorSubject이상 을 사용하면 Observable그 반대의 이점이 있습니까?

답변:


969

BehaviorSubject 는 주제 유형이며 주제는 특수한 유형의 관찰 가능하므로 다른 관찰 가능과 같은 메시지를 구독 할 수 있습니다. BehaviorSubject의 고유 한 기능은 다음과 같습니다.

  • 구독을받지 못한 경우에도 구독시 항상 값을 반환해야하므로 초기 값이 필요합니다. next()
  • 구독하면 주제의 마지막 값을 리턴합니다. 일반 옵저버 블은onnext
  • 언제든지 getValue()메소드를 사용하여 관찰 할 수없는 코드로 주제의 마지막 값을 검색 할 수 있습니다 .

관찰 가능한 대상과 비교 한 대상의 고유 한 특징은 다음과 같습니다.

  • 옵저버 블일뿐 아니라 옵저버이므로 구독하는 것 외에 대상에게 값을 보낼 수도 있습니다.

또한의 asObservable()메소드를 사용하여 동작 주제에서 관찰 가능 항목을 얻을 수 있습니다 BehaviorSubject.

Observable 은 Generic이고 BehaviorSubjectBehaviorSubject는 특정 품질을 가진 Observable이므로 기술적으로 Observable의 하위 유형입니다.

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

관측은 모두 만들 수 있습니다 SubjectBehaviorSubject사용 subject.asObservable().

유일한 차이점은 next()메소드를 사용하여 관찰 가능 값으로 값을 보낼 수 없다는 것입니다.

Angular 서비스에서는 BehaviorSubject구성 요소 및 동작 주체가 구성 요소 가이 데이터에 가입 한 이후 새로운 업데이트가 없어도 서비스를 소비하는 구성 요소가 마지막 업데이트 된 데이터를 수신하기 전에 각도 서비스가 종종 초기화되기 때문에 데이터 서비스에 사용하려고합니다.


7
나는 일반 주제의 예 2와 약간 혼동됩니다. subject.next ( "b")를 사용하여 주제에 값을 전송하는 두 번째 행에서 구독이 아무것도 얻지 못하는 이유는 무엇입니까?
jmod999

25
@ jmod999 두 번째 예는 구독이 호출되기 직전에 값을받는 일반 주제입니다. 일반 주제에서는 구독이 호출 된 후 수신 된 값에 대해서만 구독이 트리거됩니다. 구독 직전에 a가 수신되므로 구독으로 전송되지 않습니다.
Shantanu Bhadoria

환상적인 해결책에 대한 메모, 함수에서 사용하고 반환하면 관찰 가능 항목을 반환하십시오. 주제를 반환하는 데 문제가 있었으며 Observables 만 알고있는 다른 개발자들을 혼란스럽게합니다.
sam

8
수요일에 Angular 4 인터뷰가있었습니다. 여전히 새로운 플랫폼을 배우고 있기 때문에 "게으른로드되지 않은 모듈에있는 Observable을 구독하면 어떤 일이 일어 날까?" 확실하지는 않았지만 대답은 BSubject를 사용하는 것이라고 대답했습니다. 정확하게 Bhadoria가 위에서 설명한 방법입니다. 대답은 항상 최신 값을 반환하기 때문에 BSubject를 사용하는 것이 었습니다 (적어도 면접관의 최종 의견을 기억하는 방법입니다).
bob.mazzo

1
@ bob.mazzo 왜 그 경우에 BSubject를 사용해야합니까? -관찰자에 가입하면 관찰자가 초기화되지 않아 데이터를 관찰자에게 푸시 할 수 없으므로 BSubject를 사용하면 동일한 이유로 인해 아무것도받지 못하므로 아무것도받지 못합니다. 두 경우 모두 가입자는 초기화되지 않은 모듈 내에 있기 때문에 아무 것도받지 않습니다. 내가 맞아?
Rafael Reyes

183

관찰 가능 : 관찰자마다 다른 결과

하나의 매우 중요한 차이점. Observable은 단순한 함수이므로 상태가 없으므로 모든 새로운 Observer에 대해 Observable 작성 코드를 반복해서 실행합니다. 결과 :

코드는 각 관찰자에 대해 실행됩니다. HTTP 호출 인 경우 각 관찰자에 대해 호출됩니다.

이로 인해 주요 버그와 비효율이 발생합니다

BehaviorSubject (또는 Subject)는 관찰자 세부 정보를 저장하고 코드를 한 번만 실행하며 결과를 모든 관찰자에게 제공합니다.

전의:

JSBin : http://jsbin.com/qowulet/edit?js, 콘솔

// --- 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                          ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛

3
에서 온 사람은 다음 과 비교하여 KnockoutJS's ko.observable()더 많은 유사점을 즉시 보게 Rx.BehaviorSubject됩니다.Rx.Observable
Simon_Weaver

@Skeptor Observable : subscribe 메소드는 항상 옵저버와 연관된 onNext 메소드를 트리거하고 리턴 값을 가져옵니다. BehaviourSubject / Subject : 스트림에서 항상 최신 값을 반환합니다. 여기서 주제와 함께 서브 크리 브 방법은 스트림에서 최신 값을 찾을 때까지 옵저버의 onNext 메소드를 트리거하지 않습니다.
Mohan Ram

62

관찰 가능 하고 주제 모두 관찰자가 그들을 추적 할 수 있습니다 관찰의 수단이다. 그러나 둘 다 독특한 특성을 가지고 있습니다. 또한 총 3 가지 유형의 주제가 있으며, 각각의 주제에는 고유 한 특징이 있습니다. 그들 각각을 이해하려고 노력하십시오.

stackblitz 에서 실제 예제를 찾을 수 있습니다 . (실제 출력을 보려면 콘솔을 확인해야합니다)

여기에 이미지 설명을 입력하십시오

Observables

차갑습니다. 최소한 하나의 관찰자가 있으면 코드가 실행됩니다.

데이터 사본 생성 : Observable은 각 관찰자에 대한 데이터 사본을 생성합니다.

단방향 : 관찰자는 관찰 가능 (원점 / 마스터)에 값을 할당 할 수 없습니다.

Subject

그들은 뜨겁다 : 관찰자가없는 경우에도 코드가 실행되고 가치가 방송됩니다.

데이터 공유 : 모든 관찰자간에 동일한 데이터가 공유됩니다.

양방향 : 관찰자는 관찰 가능 (원점 / 마스터)에 값을 할당 할 수 있습니다.

주제를 사용하는 경우 관찰자를 작성하기 전에 브로드 캐스팅되는 모든 값을 놓치게됩니다. 여기에 Replay Subject 가 온다

ReplaySubject

그들은 뜨겁다 : 관찰자가없는 경우에도 코드가 실행되고 가치가 방송됩니다.

데이터 공유 : 모든 관찰자간에 동일한 데이터가 공유됩니다.

양방향 : 관찰자는 관찰 가능 (원점 / 마스터)에 값을 할당 할 수 있습니다. ...을 더한

메시지 스트림 재생 : 재생 제목을 구독 할 때 브로드 캐스트 된 모든 메시지가 수신됩니다.

주제 및 재생 주제에서는 초기 값을 관찰 가능으로 설정할 수 없습니다. 여기에 행동 주제가 온다

BehaviorSubject

그들은 뜨겁다 : 관찰자가없는 경우에도 코드가 실행되고 가치가 방송됩니다.

데이터 공유 : 모든 관찰자간에 동일한 데이터가 공유됩니다.

양방향 : 관찰자는 관찰 가능 (원점 / 마스터)에 값을 할당 할 수 있습니다. ...을 더한

메시지 스트림 재생 : 재생 제목을 구독 할 때 브로드 캐스트 된 모든 메시지가 수신됩니다.

초기 값을 설정할 수 있습니다 : 관측 값을 기본값으로 초기화 할 수 있습니다.


3
a ReplaySubject에는 히스토리가 있으며 일련의 (오래된) 값을 브로드 캐스트 / 방출 할 수 있습니다. buffer가 1로 설정된 경우에만 a와 유사하게 작동합니다 BehaviorSubject.
Wilt

28

Observable 객체는 푸시 기반 컬렉션을 나타냅니다.

Observer 및 Observable 인터페이스는 관찰자 디자인 패턴이라고도하는 푸시 기반 알림에 대한 일반화 된 메커니즘을 제공합니다. Observable 객체는 알림을 보내는 객체 (제공자)를 나타냅니다. Observer 객체는 객체를받는 클래스 (관찰자)를 나타냅니다.

Subject 클래스는 Observable과 Observer를 모두 상속합니다. 이는 Observable과 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 에 대한 추가 정보


subscription.dispose ()와 subscription.unsubscribe ()의 차이점은 무엇입니까?
choopage

4
@choopage 아무런 차이가 없습니다. 후자는 새로운 방법이다
Royi Namir

주제가 삭제되기 전에 구독을 취소해야합니다. 그렇지 않으면 구독이 널값을 구독하므로 가비지가됩니다.
Sophie Zhang

20

예제에서 볼 수없는 한 가지는 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);

11

관찰은 당신이 반면에만 가입 할 수 있습니다 주제 모두 게시하고 구독 당신을 수 있습니다.

따라서 주제를 사용하면 서비스 를 게시자 및 가입자 모두로 사용할 수 있습니다 .

현재로서는 실력이 좋지 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 . 제공 응용 프로그램에이 서비스를 .

로 가져 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();
  }
}

그게 다야.

지금, 임의의 값을 입력 내부 #messagehome.component.html에 출력한다 {{message}}안쪽app.component.html


왜 거대한 이미지입니까? 귀하의 답변과 직접 관련이없는 경우 투표 미끼처럼 보입니다.
ruffin

@ruffin 이것은 평균 투표 수의 평균 답변입니다. 내 프로필을보세요. 투표권 미확정 : D
Mohammed Zameer

1
나는 먼저 당신에게 공감대를 주었지만, 당신은 왜 이미지가 있는지에 대한 질문을 피했다. 답변과 직접 관련이 없습니다. 많은 담당자가 있는지 여부는 중요하지 않습니다 . 이미지가 직접적이고 명확하게 설명되어 있지 않은 경우 이미지를 제거하도록 요청합니다 . /
shrug

1
@ruffin 커뮤니티 동의에 위배되는 경우 반드시 거기에 있지 않아야합니다!
모하메드 자 메르

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

BehaviorSubjectObservable : RxJS에는 옵저버와 옵저버 블이 있으며 Rxjs는 데이터 스트림과 함께 사용할 수있는 여러 클래스를 제공하며 그 중 하나는 BehaviorSubject입니다.

Observables : Observables는 시간이 지남에 따라 여러 값의 게으른 모음입니다.

BehaviorSubject : 초기 값이 필요하고 현재 값을 새로운 가입자에게 내 보냅니다.

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

Observables 는 물이 흐르는 파이프, 때로는 물이 흐르고 때로는 흐르지 않는 파이프로 생각하십시오 . 어떤 경우에는, 당신은 실제로 항상 물이 파이프를해야합니다, 당신은 항상 아무리 작은 물을 포함하지 않는 특수 파이프를 생성하여이 작업을 수행 할 수 있습니다,이 특별한 파이프를 호출 할 수 있습니다 BehaviorSubject을 하면 될 일 경우, 지역의 수도 공급 업체 인 경우 새로 설치된 파이프가 제대로 작동한다는 것을 알고 밤에 평화롭게 잠을 잘 수 있습니다.

기술 용어로 : Observable에 항상 가치가 있어야하는 유스 케이스가 발생할 수 있습니다. 시간이 지남에 따라 입력 텍스트의 값을 캡처하려는 경우 BehaviorSubject 인스턴스를 작성하여 이러한 종류의 동작을 보장 할 수 있습니다.


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

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

그런 다음 "value"를 사용하여 시간에 따른 변경 사항을 샘플링 할 수 있습니다.


firstNameChanges.value;

이것은 Observable을 나중에 결합 할 때 BehaviorSubject로 스트림 유형을 살펴보면 스트림이 최소한 한 번 이상 실행되거나 신호를 보내 도록 할 수 있습니다 .

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.