I've googled the issue expecting that there's been a gazillion curious people before me asking it too. For some reason, most hits are on scan vs reduce (which I clearly understand). So there's a risk that I totally misunderstood the docs.
According to the docs, scan(...) will snatch an emitted value, do stuff to it and then, optionally pass it on to the next person in line. Meanwhile, subscribe(...), although accepting parameters for handling of errors and completion, does the very same thing.
I understand the "difference" between them but it appears to me as rather insignificant from the aspect of development tooling. Is it as simple as that the former only a convenience method for cases where the latter would require mundane coding? Or is there a fundamental difference between them (as in: something I can do with scanning that I can't achieve subscribing)?
Scan() and Subscribe() are quite different concepts in RxJS.
Scan is an operator for combining values coming through the stream with previous values that came through the stream, and then outputting some combination of them (I think scan and reduce are the only operators that does this). Subscribe only works on the current value that comes through the stream.
Subscribe is a special method and one of the most important concepts in RxJS. Subscribe comes at the end of the Observable stream, this is where you can use the resulting value for something. From all other operators you return something that can be passed down the chain, but you do not return from subscribe.
If you are working with cold Observables (which you very often are), you need to subscribe to it in order for the code to run at all. If you have no subscriptions on a cold observable, then none of the code in your Observable stream will run.
The syntax for using them is also different. Scan is an operator that you chain inside the pipe() method like map, reduce, filter, tap, mergeMap, flatMap, etc. It looks like:
myObservable$.pipe(map(...), scan(...), flatMap(...));
Subscribe is a method like pipe that you dot chain, like:
myObservable$.pipe(...).subscribe(...);
Related
I have not been able to find any normative text to answer this question. I have been using this code pattern (this is in TypeScript in an Angular application):
observeSomethingFun$: Observable<Fun>;
...
async loadsOfFun() {
const fun = await this.observeSomethingFun$.toPromise();
// I now have fun
}
In general, Observables need to be unsubscribed from. This happens automatically when the Angular async pipe is used but what happens in this case? Does toPromise unsubscribe after emitting one value?
If not, how do I unsubscribe manually?
Update:
It turns out #Will Taylor's answer below is correct but my question needs some clarification.
In my case the Observable emits a never-ending stream, unlike for example Angular's HttpClient Observables that complete after emitting one value. So
in my case I would never get past the await statement according to Taylor's answer.
RxJS makes this easy to fix. The correct statement turns out to be:
const fun = await this.observeSomethingFun$.pipe(first()).toPromise();
The RxJS first operator will receive the first value and unsubscribe from the source Observable. it will then send out that value to the toPromise operator
and then complete.
No need to unsubscribe.
Which is convenient, as there is no way to unsubscribe from a promise.
If the Observable completes - the promise will resolve with the last value emitted and all subscribers will automatically be unsubscribed at this point.
If the Observable errors - the promise will reject and all subscribers will automatically be unsubscribed at this point.
However, there are a couple of edge cases with toPromise in which the behavior is not completely clear from the docs.
If the Observable emits one or more values but does not complete or error, the promise will neither resolve or reject. In this case, the promise would hang around in memory, which is worth considering when working with toPromise.
If the Observable completes but does not emit a value, the promise will resolve with undefined.
First of all, thank you for this question and answer, I wrongly assumed toPromise() knew what it was doing in all scenarios and would unsubscribe when that observable completes (even if it is an observable stream)
So I will just say that it doesn't hurt to pipe all of your observables before using .toPromise()
I just went through a big ordeal of stepping through our app for memory leaks and found the above answer by Will to be good. The elaboration on the actual question was exactly the same issue I was running into.
We are stepping through each observable in the app right now and we use either
pipe(take(1)) which is equivalent to pipe(first()).
or we use pipe(takeUntil(this.destroyed)) where this.destroyed.next(true) is called when we destroy our particular component or service.
We use take() to keep our verbiage consistent so we can search for take or takeUntil across various components.
Long story short, yeah you might take a very slight performance hit piping your observables at each instance, but I highly recommend doing so in order to prevent any unwanted app-wide memory leak hunts. Then maybe if you have the time you can step through each one and see where .toPromise() actually unsubscribes correctly for you.
I was playing around with the switchMap operator to clearly understand what was happening to a "switched" inner observable.
At first i thought that switchMap was only "unsubscribing" from the switched inner observable, but then i realize it was in fact "unsubscribing AND completing" the inner observable.
To confirm that i've written this small snippet:
https://codesandbox.io/s/relaxed-meninsky-c5jmw?fontsize=14
As you can see, the finalize() operator is correctly called when the subject emit for the second time, but:
why does the complete handler of the tap operator is not called ?
This somehow make feel only 80% happy with my understanding of this operator.
A related not on that:
I've read and watch numerous sources regarding switchMap, including:
This (great) ngconf sources: https://medium.com/#shairez/a-super-ninja-trick-to-learn-rxjss-switchmap-mergemap-concatmap-and-exhaustmap-forever-88e178a75f1b
The official rxjs doc: https://rxjs-dev.firebaseapp.com/api/operators/switchMap
And none of them clearly state if inner observable is unsubscribed or unsubcribed AND closed ( or at least i did not understand it :) )
I've watched the switchMap operator source code and there is no mention to takeXXX operator, how can he complete the inner operator without that ?
tl;dr
Do you confirm that switchMap complete inner observable when switching ?
Why does tap operator does not work as expected ?
If switchMap effectively complete inner observable how can he do that without using a takeXXX operator internally ?
I think you are confusing the difference between unsubscribe() and complete(). For a hot observable like a Subject you can "stop" it in a few ways. From the 'top->down' with complete() as you did in your example, or from the 'bottom->up' with unsubscribe().
switchMap() does exactly what it says, it switches from the primary observable to a secondary (or 'inner') observable. That is why when you complete() the outer observable, it has no effect on the inner one - the chain has been switched. To affect the chain (as opposed to just affecting the Subject which is the source observable), you need to get a reference to the Subscriber, and then call that Subscriber's unsubscribe() method.
To see this, I've forked your CodeSandbox and produced this new one
As you will see in that CodeSandbox I have added a few more lines to show what is going on:
Note the new tap() in the chain right above the switchMap - this will show what is going on directly from the Subject() before the chain is switched to a different Observable with the switchMap operator.
The Subscription for the chain is now being captured in the variable sub which can be unsubscribed later to affect the chain from the bottom->up.
Note that the s.complete() after 10 seconds is now reflected in the Subject, and note also how it doesn't affect the chain at all.
Now note that the new sub.unsubscribe() after 15 seconds indeed kills the chain.
uncomment the take(5) in the newT() method to see that indeed the tap's complete method will be called if the source above it actually completes (top->down).
finalize() catches the fact that an unsubscribe has happened (bottom->up), note that it occurs both when switchMap() does the automatic unsubscribe upwards when s.next() is called on the Subject source, as well as when unsubscribe() is called on the Subscription, which again causes a bottom->up termination. In no case is your complete() called in the original observer because the chain is never actually completed. You can complete the chain with a take(10) operator if you want, to see how that works as well.
Hopefully this helps clear up the confusion a little. :)
I often use combineLatest to combine 3 or 4 Observables to calculate a simple condition.
If one of the 'combined' Observables doesn't emit then this will block until it does. It can be very tricky to debug if later down the line something that has always emitted immediately stops emitting.
Side-note: I'm specifically needing this for UI related logic, where there may be observables that represent things like screen width / scroll position / etc. So they're supposed to always be there - but if it breaks suddenly (especially on mobile) it's difficult to track down what's blocking it.
So what I need is something like combineLatestImmediate that errors if all inputs aren't immediately available. When I say 'available right away' it's typically something that comes from a centralized data store, or a behaviorsubject (which of course will always have a value). But when it breaks...ugh.
Is there a better way than:
combineLatest(obs1, obs2, obs3)
.pipe(timeoutWith(0, throwError('Expected obs all to be available')))
or even:
// note: take(1) is required or the wrong observable
// may get reported if the source hasn’t closed
combineLatest(obs1.pipe(take(1), timeoutWith(0, throwError('obs1 has no value'))),
obs2.pipe(take(1), timeoutWith(0, throwError('obs2 has no value'))),
obs3.pipe(take(1), timeoutWith(0, throwError('obs3 has no value'))));
You could put a non zero value for timeout if you wanted a grace period, or make this into a custom operator. But I'm finding a need more and more for this.
It's a safety / sanity thing, to save time debugging.
Also I'm not looking for forkJoin (which short-circuits if any of the inputs are EMPTY). I'm talking about when a value is just not immediately available - usually .
What's the difference between RxJS and IxJS, and when would I want to use one over the other?
From the IxJS docs:
RxJS is great for event-based workflows where the data can be pushed at the rate of the producer, however, IxJS is great at I/O operations where you as the consumer can pull the data when you are ready.
After going through the docs, the only major difference seems to be the concept of Iterables in IxJS and Observables in RxJS.
Both Iterables and Observables execute either synchronously or asynchronously, and the .forEach from IxJS is essentially the same as RxJS's .subscribe method when paired with the almost-identical from creator function. The only other difference is IxJS's .forEach method is optional because you could use the imperative for-of instead.
It seems like there are two libraries for no reason because RxJS's from creator function can convert Iterables to Observables.
From my perspective, it's not really IxJS and RxJS, it's Iterables and Observables. How are they different and when would you use one over the other?
tl;dr
RxJS processes values as soon as they arrive. It's a push system.
IxJS specifies when to pass in the next value. It's a pull system.
Explanation
IxJS may be helpful if want to have pull-based model, for example, when dealing with backpressure.
As you can see in the documentation:
IxJS unifies both synchronous and asynchronous pull-based collections, just as RxJS unified the world of push-based collections. RxJS is great for event-based workflows where the data can be pushed at the rate of the producer, however, IxJS is great at I/O operations where you as the consumer can pull the data when you are ready.
In other words:
Use RxJS if your producer (usually User) is slower that processing of data (this is common for frontend).
Use IxJS if your producer (usually System) is much faster than you can process data (more common for the backend).
To understand what this means, consider the following example:
You need to build ETL pipeline and process a large file (about 1TB).
If you write it with RxJS, something like:
readFileByLineObservable('path/to/file')
.pipe(
doSomeHeavyTransformation(),
)
.subscribe()
Then readFileByLineObservable will try to "push" the entire file of 1TB into RAM as soon as possible. Only after this occurs, you will start to do doSomeHeavyTransformation. This problem is called backpressure.
In contrast, IxJS will try to "pull" each newline only after previous line was processed. That's the optimal processing method in this case.
The difference is how RxJS's .subscribe sets up a listener whereas IxJS's .forEach tells its iterator when to give the next value (only after its done processing the first one. It's similar to, but not the same as, RxJS's concatMap and concatAll operators.
As a complement to Oles Savluk answer, I found Matt Podwysocki's explanation particularly useful (https://gist.github.com/mattpodwysocki/1d0fe43961c6222571386568b8a5ef23):
we have four types of collections, each with their own purpose. Each
has its own place, and there's no one solution that rules them all.
Pull: Iterable - purely synchronous data, either finite or infinite
Push: Observable / Subject/Observer - eventual data such as DOM events, collections over time
Pull/Push: AsyncIterable - I/O or other asynchronous data where the consumer needs to be in control
Push/Pull: AsyncObservable - Network calls where creation/teardown may be asynchronous as well as projections may be asynchronous too.
Matt is a contributor to both RxJS and IxJS.
Iterable and AsyncIterable come from IxJS, Observable and AsyncObservable are developed in RxJS
Below are the advantages i have read in URL: Angular - Promise vs Observable
promise:
returns a single value
not cancelled
more readable code with try/catch and async/await
observable
works with multiple values over time
cancellable
supports map, filter, reduce and similar operators
use Reactive Extensions (RxJS)
an array whose items arrive asynchronously over time
In observable i see 3 & 4 Point as supports operators and RXJS. I just have a basic question like can't i use RXJS and operators with promises? what is the meaning of point 5
In short, no you can't use those operators (like map, filter) directly on a Promise.
Rxjs does provide an operator toPromise which does convert an Observable to a Promise - if that is your preference.
I think point 5 is actually conflated with point 1. Point 1 is the crux of what Observables are all about: dealing with 0 to n values over time.
You may not think that to be useful if you're used to using Promises simply for Ajax requests - e.g. hit an endpoint and get a value back. But in the case of Observables, you can use them in any context - for example, DOM events.
If you were to create an Observable via listening to a Mouseover event, then you'd be receiving n values over any given length of time - and then you could react to these events.
When thinking in terms of Ajax requests, the classic example is that of the look ahead search input which is detailed in the link of your question.
As #Rich mentioned, rxjs Operators are aimed for continues data streams (e.g. take takes the first n next of an Observable). As such, not all operators are useful for Promise-based results.
However, given that some operators are compact/neat even for Promise, you can use the following:
import { from, firstValueFrom, delay } from "rxjs";
...
// converts to Observable and back to Promise
firstValueFrom(from(myPromise).pipe(delay(1000))