Difference between RxJS and IxJS? - rxjs

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

Related

Difference between scan(...) and subscribe(...) in rxjs

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(...);

How many "temperatures" are there for a Rx Observable?

All over the Rx.Net literature there are references to what is commonly know as the temperature of an observable.
There are cold observables (like the ones created by Observable.Interval() and similar factory methods), which will create side effects every time that a new Subscription is created.
On the other side of the spectrum there are hot observables (like Subject<T>) which will onboard new subscriptions as they come.
There are also warm observables, like the ones returned by RefCount() which will execute the initialisation every time one subscription is created, but only if there was no other active subscription. The behaviour of these warm observables is explained here by Dave Sexton:
Alternatively, you can call Publish then RefCount to get an IObservable that is shared among multiple consecutive observers. Note that this isn't truly a hot observable - it's more like a warm observable. RefCount makes a single subscription to the underlying observable while there's at least one observer of your query. When your query has no more observers, changing the reference count to 0, the underlying subscription is disposed. If another observer subscribes to your query later, moving the reference count from 0 to 1 again, then RefCount makes a new subscription to the underlying observable, causing subscription side-effects to occur again.
Are there any other temperatures that one should be aware of? Is it possible to obtain programmatically the temperature of an Observable?
Easy question first:
Is it possible to obtain programmatically the temperature of an Observable?
No. Best you can do is subscribe and see what happens.
The observable 'contract' specifies that when you subscribe to an observable you get zero or more OnNext messages, optionally followed by either one OnCompleted or one OnError message. The contract doesn't specify anything about how multiple or earlier/later subscribers are treated, which is what observable 'temperature' is mostly concerned with.
Are there any other temperatures that one should be aware of?
I wouldn't even think of it in such concrete or discrete terms as you have specified.
I think of it in terms of on-subscribe effects: The coldest of observables have all their effects happen on subscribe (like Observable.Return(42)). The hottest of observables have no effects happening on subscribe (new Subject<int>()). In between those two poles is a continuum.
Observable.Interval(TimeSpan.FromMilliseconds(100)) for example will emit a new number every 100 milliseconds. That example, unlike Observable.Return(42), could be mostly 'warmed-over' via .Publish().RefCount(): The first subscriber starts the numbers, but the second subscriber will see the only the latest numbers, not starting from 0. However, if instead of .Publish() you did .Replay(2).RefCount(), then you have some on-subscribe effects going on. Do the Publish and Replay observables have the same 'temperature'?
TL;DR: Don't focus on the classifications that much. Understand the difference between the two and know that some observables have colder properties and some have warmer ones.

Is it possible to use operators like map, filter etc with promises

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

How to cache a reactive publisher like Observable?

I'm trying to understand what happens if I cache the result of a method returning a cold Observable? The flow has not been materialized yet, so what does the cache actually contain? I tried to find out using Hazelcast and Spring Boot but couldn't get the cache working.
Edit:
When I say cache not working, I am speaking based on what I see from Hazelcast Management Center. Depending on the cache config (I tried many things), either the cache shows up but no entries, or the cache doesn't show up at all.
Example:
#javax.cache.annotation.CacheResult
Observable<Integer> random() {
// Do I get a new number every time?
return Observable.just(new Random().nextInt());
}
From rx-java wiki (source here):
A cold Observable emits a particular sequence of items, but can begin
emitting this sequence when its Observer finds it to be convenient,
and at whatever rate the Observer desires, without disrupting the
integrity of the sequence. For example if you convert a static
Iterable into an Observable, that Observable will emit the same
sequence of items no matter when it is later subscribed to or how
frequently those items are observed. Examples of items emitted by a
cold Observable might include the results of a database query, file
retrieval, or web request.
With cold Observable, like your example, the request is done at subscribe time, for each subscriber. Even without cache, if you subscribe twice to the same Observable, the request will occur twice. The Observable is not bound to a specific stream. Observable is just a contract describing how to access data.
Caching the result of a method returning an Observable is I think somewhat similar to storing the result to a local property; you just avoid to recreate the Observable object again later. But just the 'getter', not the data.
rx-java give some tools to achieve caching by it's own. You could have a look to Subject or ConnectableObservable.

Concrete example for comparing Rxjs event handling and Promise

All:
I am very new to Rx.js( I heard this name from a tech meeting ), what im curious about is how to use it in real project(or say what is its usercase), and could anyone give me an example in which situation that a job Rx.js can do but Promise can not do(or just much easier to do in Rx.js)?
Thanks
Your question is too vague and open-ended. I recommend doing some reading, but if you want the short version:
Observables...
Return a logical "infinite" number of values and a "completion" when this "infinite sequence" concludes, or throw an error
Have a Creation/Subscription/Disposal lifecycle
Can actually model a series of HTTP requests and their cancellation
Are based on functional programming techniques and are reactive
Are very good for modeling async data flows
Are lazily evaluated based on subscribers
Promises...
Return a single value asynchronously or reject/throw an error
Are created and then by definition either resolve or reject
Can model a single HTTP request that will be fulfilled
Are not really FP based (there are multiple GH issues about this, they are almost all full of drama and aren't very much worth reading)
Can only model single tasks
Are eagerly evaluating by design
Some may mistake this as an attack on Promises, but Promises are usually good enough for single-value async. But Rx users probably don't like Promises because they feel like they only have a subset of features with less features compared to Observables.

Resources