Development Tip

BehaviorSubject vs Observable?

yourdevel 2020. 10. 3. 12:07
반응형

BehaviorSubject vs Observable?


Angular RxJs 패턴을 살펴보고 있는데 a BehaviorSubjectObservable.

내 이해에서 a BehaviorSubject는 시간이 지남에 따라 변경 될 수있는 값입니다 (구독 가능하고 구독자는 업데이트 된 결과를받을 수 있음). 이것은 Observable.

언제 Observablevs a 를 사용 BehaviorSubject하시겠습니까? BehaviorSubjectover an Observable또는 그 반대로 사용하면 이점이 있습니까?


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

  • 수신하지 않은 경우에도 구독시 항상 값을 반환해야하므로 초기 값이 필요합니다. next()
  • 구독시 주제의 마지막 값을 반환합니다. 일반 관찰 가능 항목은onnext
  • 언제든지 getValue()메소드를 사용하여 관찰 할 수없는 코드에서 주제의 마지막 값을 검색 할 수 있습니다 .

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

  • 관찰자 일뿐만 아니라 관찰자이므로 구독하는 것 외에도 주제에 값을 보낼 수 있습니다.

또한 asObservable()on 메소드를 사용하여 행동 주제에서 관찰 가능 항목을 얻을 수 있습니다 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()메소드를 사용하여 Observable에 값을 보낼 수 없다는 것입니다.

Angular 서비스에서는 BehaviorSubject구성 요소와 동작 주체가이 데이터에 대한 구성 요소 구독 이후 새로운 업데이트가없는 경우에도 서비스를 사용하는 구성 요소가 마지막으로 업데이트 된 데이터를 받도록 보장하기 전에 각도 서비스가 자주 초기화되기 때문에 데이터 서비스를 사용합니다.


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

매우 중요한 차이점이 하나 있습니다. Observable은 함수일 뿐이므로 상태가 없으므로 모든 새로운 Observer에 대해 Observable 생성 코드를 반복해서 실행합니다. 결과는 다음과 같습니다.

코드는 각 관찰자에 대해 실행됩니다. 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                          │
└─────────────────────────────────────┴─────────────────────────────────────┘

Observablesubject는 모두 Observable 의 의미로 관찰자가 추적 할 수 있습니다. 하지만 둘 다 독특한 특성이 있습니다. 또한 총 3 가지 유형의 과목이 각각 고유 한 특성을 가지고 있습니다. 그들 각각을 이해하려고 노력합시다.

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

여기에 이미지 설명 입력

Observables

그들은 차갑습니다 : 최소한 한 명의 관찰자가있을 때 코드가 실행됩니다.

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

단방향 : Observer는 Observable (origin / master)에 값을 할당 할 수 없습니다.

Subject

그들은 뜨겁다 : 관찰자가 없어도 코드가 실행되고 가치가 방송된다.

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

양방향 : Observer는 Observable (origin / master)에 값을 할당 할 수 있습니다.

사용 대상을 사용하는 경우 옵저버 생성 전에 방송되는 모든 값을 놓치게됩니다. 그래서 여기에 재생 주제가 있습니다

ReplaySubject

그들은 뜨겁다 : 관찰자가 없어도 코드가 실행되고 가치가 방송된다.

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

양방향 : Observer는 Observable (origin / master)에 값을 할당 할 수 있습니다. ...을 더한

메시지 스트림 재생 : 재생 제목을 구독 할 때와 상관없이 방송 된 모든 메시지를 받게됩니다.

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

BehaviorSubject

그들은 뜨겁다 : 관찰자가 없어도 코드가 실행되고 가치가 방송된다.

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

양방향 : Observer는 Observable (origin / master)에 값을 할당 할 수 있습니다. ...을 더한

메시지 스트림 재생 : 재생 제목을 구독 할 때와 상관없이 방송 된 모든 메시지를 받게됩니다.

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


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

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

Subject 클래스는 옵저버이자 옵저버 블이라는 점에서 Observable과 Observer를 모두 상속합니다. 주제를 사용하여 모든 관찰자를 구독 한 다음 해당 주제를 백엔드 데이터 소스에 구독 할 수 있습니다.

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 에 대한 자세한 내용


One thing I don't see in examples is that when you cast BehaviorSubject to Observable via asObservable, it inherits behaviour of returning last value on subscription.

It's the tricky bit, as often libraries will expose fields as observable (i.e. params in ActivatedRoute in Angular2), but may use Subject or BehaviorSubject behind the scenes. What they use would affect behaviour of subscribing.

See here 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);

An observable allows you to subscribe only whereas a subject allows you to both publish and subscribe.

So a subject allows your services to be used as both a publisher and a subscriber.

As of now, I'm not so good at Observable so I'll share only an example of Subject.

Let's understand better with an Angular CLI example. Run the below commands:

npm install -g @angular/cli

ng new angular2-subject

cd angular2-subject

ng serve

Replace the content of app.component.html with:

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

<app-home>
</app-home>

Run the command ng g c components/home to generate the home component. Replace the content of home.component.html with:

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

#message is the local variable here. Add a property message: string; to the app.component.ts's class.

Run this command ng g s service/message. This will generate a service at src\app\service\message.service.ts. Provide this service to the app.

Import Subject into MessageService. Add a subject too. The final code shall look like this:

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

Now, inject this service in home.component.ts and pass an instance of it to the constructor. Do this for app.component.ts too. Use this service instance for passing the value of #message to the service function 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);
  }
}

Inside app.component.ts, subscribe and unsubscribe (to prevent memory leaks) to the 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();
  }
}

That's it.

Now, any value entered inside #message of home.component.html shall be printed to {{message}} inside app.component.html


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

BehaviorSubject vs Observable : RxJS has observers and observables, Rxjs offers a multiple classes to use with data streams, and one of them is a BehaviorSubject.

Observables : Observables are lazy collections of multiple values over time.

BehaviorSubject:A Subject that requires an initial value and emits its current value to new subscribers.

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

참고URL : https://stackoverflow.com/questions/39494058/behaviorsubject-vs-observable

반응형