117

I wonder, if there is any difference in performance between using .take(1) and .unsubscribe when unsubscribe is used right after the subscription:

var observable = Rx.Observable.interval(100);

First:

var subscription = observable.subscribe(function(value) {
   console.log(value);
}).unsubscribe();

Second:

var subscription = observable.take(1).subscribe(function(value) {
    console.log(value);
});

Any ideas of it makes any different regard the performance?

pjpscriv
  • 866
  • 11
  • 20
TheUnreal
  • 23,434
  • 46
  • 157
  • 277
  • 6
    `var subscription = observable.subscribe({function A}).unsubscribe();` will not work as expected incase funcation A will be called after javascrit will finish excute this line. So insted of getting only one value, you will get zero values. It is recommneded to subscribe manually and use take(..) or other methods like take that deals with the subscription for you. – Stav Alfi Nov 12 '16 at 15:14

2 Answers2

176

Each serves a different purpose so it's hard to compare them.

In general if you take this source:

const source = range(1,3);

... and consume it with subscribe() followed immediately by unsubscribe():

source.subscribe(
  console.log,
  undefined, 
  () => console.log('complete')
).unsubscribe();

... then all values from source are going to be emitted even though we called unsubscribe() right after subscribing. This is because the code is still strictly sequential (synchronous) and the source is a cold Observable.

1
2
3
complete

Btw, try adding delay(0) operator to make source.pipe(delay(0)).subscribe(...).unsubscribe(). This makes emitting values asynchronous using an actual setTimeout() call and for this reason unsubscribe() is called before any next handlers and is discarded immediately.

In other words unsubscribe() let's you stop receiving values anytime. Even when the source hasn't emitted any value (we never receive any complete notification).

Using take() operator limits the chain to only emit a specific number of values.

source.pipe(
  take(1),
)
.subscribe(
  console.log,
  undefined,
  () => console.log('complete')
);

This just emits a single value and completes:

1
complete

Even if you add .unsubscribe() the result would be the same.

See live demo: https://stackblitz.com/edit/rxjs-tbu5kb

So take() is an operator while unsubscribe() is a method on a Subscription object. These two things are often interchangeable but they never fully substitute each other.

Jan 2019: Updated for RxJS 6

martin
  • 93,354
  • 25
  • 191
  • 226
  • 79
    hi @martin does take(1) do unsubscription? If I add take(1), do I have to call unsubscribe again? Thanks – fifth Jul 12 '17 at 01:14
  • 134
    @fifth No, you don't. When the chain completes it recursively calls all dispose handlers so you don't need to call `unsubscribe` yourself. – martin Jul 12 '17 at 07:04
  • 13
    fifth, @martin - could you make a question and answer from these two comments? I actually looked for this specific question ('does take-1 do unsubscribe?') and got into this question accidentaly. Judging from the unusually high amount of upvotes on your comments, other people seem to agree ;) Or at least add/interleve it into the current Q&A in some visible way. The fact that take-X (or, any 'completion' of a stream) do unsubscribe is really important, and I can't find any Q&A that would touch that matter and give definitive and clear answer like martin's comment here. – quetzalcoatl Jan 09 '19 at 10:38
  • 2
    @quetzalcoatl It calls unsubscribe if you see the source code. https://github.com/ReactiveX/rxjs/blob/master/src/internal/operators/take.ts#L95 – Tengis Jun 06 '19 at 09:28
  • 1
    Be careful, if by any reason it doesn't take one (or any number of count) it doesn't unsubscribe. – Farhad May 07 '20 at 23:48
63

Just keep in mind that take(1) still doesn’t unsubscribe when component is being destroyed. The subscription remains active until first value is emitted no matter if component is active or destroyed. So if we do something more crazy, like accessing the DOM, in our subscription — we might end up with an error in the console.

https://medium.com/angular-in-depth/the-best-way-to-unsubscribe-rxjs-observable-in-the-angular-applications-d8f9aa42f6a0

Tim
  • 5,435
  • 7
  • 42
  • 62
el peregrino
  • 741
  • 5
  • 9
  • and what is the solution for unsubscribe? dont use take, and replace it with takeUntil(this.destroyable$), this.destroyable$ is subject in separate component which will next on ngOnDestroy – pinarella Apr 06 '23 at 10:28
  • @pinarella that linked article has several potential solutions, including the most common approaches for unsubscribing when a component is destroyed. If you need help for a specific solution then create a question and post full details. – kh42874 Apr 27 '23 at 14:48