ChatGPT解决这个技术问题 Extra ChatGPT

What is the difference between Subject and BehaviorSubject?

I'm not clear on the difference between a Subject and a BehaviorSubject. Is it just that a BehaviorSubject has the getValue() function?

@dev I agree...

K
Kad

A BehaviorSubject holds one value. When it is subscribed it emits the value immediately. A Subject doesn't hold a value.

Subject example (with RxJS 5 API):

const subject = new Rx.Subject();
subject.next(1);
subject.subscribe(x => console.log(x));

Console output will be empty

BehaviorSubject example:

const subject = new Rx.BehaviorSubject(0);
subject.next(1);
subject.subscribe(x => console.log(x));

Console output: 1

In addition:

BehaviorSubject should be created with an initial value: new Rx.BehaviorSubject(1)

Consider ReplaySubject if you want the subject to get previously publised values.


So do you mean you have to subscribe to subject before subject.next() to for this to work?
@eric for Subject, yes. That is the distinction.
Note that you have to pass in the first value to BehaviorSubject's constructor ;)
if we create subject with boolean even subject emits rite?? const subject = new Subject(); subject.next(true);
If it helps: Subjects = Event - BehaviorSubject = State;
S
Sergey

BehaviourSubject

BehaviourSubject will return the initial value or the current value on Subscription

var bSubject= new Rx.BehaviorSubject(0);  // 0 is the initial value

bSubject.subscribe({
  next: (v) => console.log('observerA: ' + v)  // output initial value, then new values on `next` triggers
});

bSubject.next(1);  // output new value 1 for 'observer A'
bSubject.next(2);  // output new value 2 for 'observer A', current value 2 for 'Observer B' on subscription

bSubject.subscribe({
  next: (v) => console.log('observerB: ' + v)  // output current value 2, then new values on `next` triggers
});

bSubject.next(3);

With output:

observerA: 0
observerA: 1
observerA: 2
observerB: 2
observerA: 3
observerB: 3

Subject

Subject does not return the current value on Subscription. It triggers only on .next(value) call and return/output the value

var subject = new Rx.Subject();

subject.next(1); //Subjects will not output this value

subject.subscribe({
  next: (v) => console.log('observerA: ' + v)
});
subject.subscribe({
  next: (v) => console.log('observerB: ' + v)
});

subject.next(2);
subject.next(3);

With the following output on the console:

observerA: 2
observerB: 2
observerA: 3
observerB: 3

Its also more correct : "BehaviourSubject will return the initial value or the current value on Subscription" is a better explanation than "A BehaviorSubject holds one value."
I put the code above on Stackblitz: stackblitz.com/edit/rxjs-subjectvsbehaviorsubject
Where is observerB: 3?
@OPV ObserverB: 3 is there while you call subject.next(3);
p
piecioshka

I just created a project which explain what is the difference between all subjects:
https://github.com/piecioshka/rxjs-subject-vs-behavior-vs-replay-vs-async

https://i.stack.imgur.com/VyiFf.png


simple and superb hints..Thanks!
Wow, I wish the official documentation would be that simple and helpful, thanks!
M
Moshe Yamini

BehaviorSubject keeps in memory the last value that was emitted by the observable. A regular Subject doesn't.

BehaviorSubject is like ReplaySubject with a buffer size of 1.

UPDATE: There are edge use cases that distinguish those two. https://medium.com/javascript-everyday/behaviorsubject-vs-replaysubject-1-beware-of-edge-cases-b361153d9ccf

TLDR: If you want to provide an initial value at subscription time, even if nothing has been pushed to a Subject so far, use the BehaviorSubject. If you want to have the last value replayed to an observer, even if a Subject is already closed, use the ReplaySubject(1).


S
Sanjeet kumar

It might help you to understand.

import * as Rx from 'rxjs';

const subject1 = new Rx.Subject();
subject1.next(1);
subject1.subscribe(x => console.log(x)); // will print nothing -> because we subscribed after the emission and it does not hold the value.

const subject2 = new Rx.Subject();
subject2.subscribe(x => console.log(x)); // print 1 -> because the emission happend after the subscription.
subject2.next(1);

const behavSubject1 = new Rx.BehaviorSubject(1);
behavSubject1.next(2);
behavSubject1.subscribe(x => console.log(x)); // print 2 -> because it holds the value.

const behavSubject2 = new Rx.BehaviorSubject(1);
behavSubject2.subscribe(x => console.log('val:', x)); // print 1 -> default value
behavSubject2.next(2) // just because of next emission will print 2 

R
Ran Turner

A BehaviorSubject holds one value (so we actually need to initialize a default value). When it is subscribed it emits that value immediately. A Subject on the other hand, does not hold a value.

That actually means that in Subject, the subscribers will only receive the upcoming value where as in BehaviorSubject the subscribers will receive the previous value and also upcoming value.

More about the difference between BehaviorSubject and Subject can be found here

So, let's take an example to see how this will behave:

let mySubject = new Subject<number>();

mySubject.subscribe(x => console.log("The first Subscription : " + x));

mySubject.next(1);
mySubject.next(2);

mySubject.subscribe(x => console.log("The second Subscription : " + x));

mySubject.next(3);

// The first Subscription : 1
// The first Subscription : 2
// The first Subscription : 3
// The second Subscription : 3

Like we saw above, the first 2 values were output from the subject before the second subscription registered, so it didn't get them, it only got the new values after subscribed. The first subscription got them all, since it subscribed before the first values were output.

Now, let's change the subject to BehaviorSubject and see the difference:

let mySubject = new BehaviorSubject<number>(0);

mySubject.subscribe((x) => console.log('The first Subscription : ' + x));

mySubject.next(1);
mySubject.next(2);

mySubject.subscribe((x) => console.log('The second Subscription : ' + x));

mySubject.next(3);

// The first Subscription : 0 (since it's the initial value)
// The first Subscription : 1
// The first Subscription : 2
// The second Subscription : 2 (since it's the initial value for the seconde subscriber)
// The first Subscription : 3
// The second Subscription : 3

Now, notice how the first subscriber outputs 0 since the BehaviorSubject was initialized with 0. When the second subscriber subscribes, it immediately emits the '2' value since it was the last value to be handled so it acts as the initial value for it.


@Rad thank you for you explanation -> it really made sense to me 😊
p
pradeep
BehaviorSubject keeps in memory the last value that was emitted by the observable. A regular Subject doesn't. So we can update dynamic titles based on Behaviour Subject.


var bSubject= new Rx.BehaviorSubject(0);  // 0 is the initial value
    
    bSubject.subscribe({
      next: (v) => console.log('observerA: ' + v)  // output initial value, then new values on `next` triggers
    });
    
    bSubject.next(1);  // output new value 1 for 'observer A'
    bSubject.next(2);  // output new value 2 for 'observer A', current value 2 for 'Observer B' on subscription
    
    bSubject.subscribe({
      next: (v) => console.log('observerB: ' + v)  // output current value 2, then new values on `next` triggers
    });
    
    bSubject.next(3);
    
     - With Output
    
    

J
Jeffrey Mesa

A BehaviorSubject emits a value after subscription, a Subject no.

// Subject
const mySubject = new Rx.Subject().subscribe((v) => console.log(v)); // will return nothing

// BehaviorSubject
const myBehaviorSubject = new Rx.BehaviorSubject(666).subscribe((v) => console.log(v)); // will return 666 when subscription occurs