Pipe and select operators in RxJS - rxjs

I'm wondering whether the following two blocks of code behave in the same manner:
With pipe (from original ngrx sample):
pending$ = this.store.pipe(select(fromAuth.selectLoginPagePending));
error$ = this.store.pipe(select(fromAuth.selectLoginPageError));
And without one:
pending$ = this.store.select(fromAuth.selectLoginPagePending);
error$ = this.store.select(fromAuth.selectLoginPageError);
I've tested both and haven't noticed any apparent difference.
Thoughts?

Yes, you are right. Both
pending$ = this.store.pipe(select(fromAuth.selectLoginPagePending));
error$ = this.store.pipe(select(fromAuth.selectLoginPageError));
and
pending$ = this.store.select(fromAuth.selectLoginPagePending);
error$ = this.store.select(fromAuth.selectLoginPageError);
carry out the same function, which is to obtain a slice of the store state , as described on the NgRX documentation on selectors.
However, the pipe() utility allows you to chain the selector with RxJS pipeable operators, such as scan(), and filter(), allowing you to carry out other operations such as state transitions.

They both do the same thing.
Internally, the store.select function calls the select operator.

Related

Observable unsubscribe inside subscribe method

I have tried to unsubscribe within the subscribe method. It seems like it works, I haven't found an example on the internet that you can do it this way.
I know that there are many other possibilities to unsubscribe the method or to limit it with pipes. Please do not suggest any other solution, but answer why you shouldn't do that or is it a possible way ?
example:
let localSubscription = someObservable.subscribe(result => {
this.result = result;
if (localSubscription && someStatement) {
localSubscription.unsubscribe();
}
});
The problem
Sometimes the pattern you used above will work and sometimes it won't. Here are two examples, you can try to run them yourself. One will throw an error and the other will not.
const subscription = of(1,2,3,4,5).pipe(
tap(console.log)
).subscribe(v => {
if(v === 4) subscription.unsubscribe();
});
The output:
1
2
3
4
Error: Cannot access 'subscription' before initialization
Something similar:
const subscription = of(1,2,3,4,5).pipe(
tap(console.log),
delay(0)
).subscribe(v => {
if (v === 4) subscription.unsubscribe();
});
The output:
1
2
3
4
This time you don't get an error, but you also unsubscribed before the 5 was emitted from the source observable of(1,2,3,4,5)
Hidden Constraints
If you're familiar with Schedulers in RxJS, you might immediately be able to spot the extra hidden information that allows one example to work while the other doesn't.
delay (Even a delay of 0 milliseconds) returns an Observable that uses an asynchronous scheduler. This means, in effect, that the current block of code will finish execution before the delayed observable has a chance to emit.
This guarantees that in a single-threaded environment (like the Javascript runtime found in browsers currently) your subscription has been initialized.
The Solutions
1. Keep a fragile codebase
One possible solution is to just ignore common wisdom and continue to use this pattern for unsubscribing. To do so, you and anyone on your team that might use your code for reference or might someday need to maintain your code must take on the extra cognitive load of remembering which observable use the correct scheduler.
Changing how an observable transforms data in one part of your application may cause unexpected errors in every part of the application that relies on this data being supplied by an asynchronous scheduler.
For example: code that runs fine when querying a server may break when synchronously returned a cashed result. What seems like an optimization, now wreaks havoc in your codebase. When this sort of error appears, the source can be rather difficult to track down.
Finally, if ever browsers (or you're running code in Node.js) start to support multi-threaded environments, your code will either have to make do without that enhancement or be re-written.
2. Making "unsubscribe inside subscription callback" a safe pattern
Idiomatic RxJS code tries to be schedular agnostic wherever possible.
Here is how you might use the pattern above without worrying about which scheduler an observable is using. This is effectively scheduler agnostic, though it likely complicates a rather simple task much more than it needs to.
const stream = publish()(of(1,2,3,4,5));
const subscription = stream.pipe(
tap(console.log)
).subscribe(x => {
if(x === 4) subscription.unsubscribe();
});
stream.connect();
This lets you use a "unsubscribe inside a subscription" pattern safely. This will always work regardless of the scheduler and would continue to work if (for example) you put your code in a multi-threaded environment (The delay example above may break, but this will not).
3. RxJS Operators
The best solutions will be those that use operators that handle subscription/unsubscription on your behalf. They require no extra cognitive load in the best circumstances and manage to contain/manage errors relatively well (less spooky action at a distance) in the more exotic circumstances.
Most higher-order operators do this (concat, merge, concatMap, switchMap, mergeMap, ect). Other operators like take, takeUntil, takeWhile, ect let you use a more declarative style to manage subscriptions.
Where possible, these are preferable as they're all less likely to cause strange errors or confusion within a team that is using them.
The examples above re-written:
of(1,2,3,4,5).pipe(
tap(console.log)
first(v => v === 4)
).subscribe();
It's working method, but RxJS mainly recommend use async pipe in Angular. That's the perfect solution. In your example you assign result to the object property and that's not a good practice.
If you use your variable in the template, then just use async pipe. If you don't, just make it observable in that way:
private readonly result$ = someObservable.pipe(/...get exactly what you need here.../)
And then you can use your result$ in cases when you need it: in other observable or template.
Also you can use pipe(take(1)) or pipe(first()) for unsubscribing. There are also some other pipe methods allowing you unsubscribe without additional code.
There are various ways of unsubscribing data:
Method 1: Unsubscribe after subscription; (Not preferred)
let localSubscription = someObservable.subscribe(result => {
this.result = result;
}).unsubscribe();
---------------------
Method 2: If you want only first one or 2 values, use take operator or first operator
a) let localSubscription =
someObservable.pipe(take(1)).subscribe(result => {
this.result = result;
});
b) let localSubscription =
someObservable.pipe(first()).subscribe(result => {
this.result = result;
});
---------------------
Method 3: Use Subscription and unsubscribe in your ngOnDestroy();
let localSubscription =
someObservable.subscribe(result => {
this.result = result;
});
ngOnDestroy() { this.localSubscription.unsubscribe() }
----------------------
Method 4: Use Subject and takeUntil Operator and destroy in ngOnDestroy
let destroySubject: Subject<any> = new Subject();
let localSubscription =
someObservable.pipe(takeUntil(this.destroySubject)).subscribe(result => {
this.result = result;
});
ngOnDestroy() {
this.destroySubject.next();
this.destroySubject.complete();
}
I would personally prefer method 4, because you can use the same destroy subject for multiple subscriptions if you have in a single page.

Should an rxjs operator return a function or an observable?

I'm a bit confused by the various definitions of an operator in rxjs.
Below I provide some of the definitions:
1 A Pipeable Operator is a function that takes an Observable as its input and returns another Observable.
Creation Operators are the other kind of operator, which can be called as standalone functions to create a new Observable
2 An operator is a function that takes one observable (the source) as its first argument and returns another observable (the destination, or outer observable)
3 Operators take configuration options, and they return a function that takes a source observable.
4 Operators should always return an Observable [..] If you create a method that returns something other than an Observable, it's not an operator, and that's fine.
Since 1,2,4 seem to be conflicting with 3, which definition is the correct one. Is there a better definition of rxjs operators?
For example: in case of map. Is map() itself the operator? Or the operator is the return value of map()?
Is map() itself the operator? Or the operator is the return value of map()?
Current implementation of the map() looks like this:
export function map<T, R>(project: (value: T, index: number) => R, thisArg?: any): OperatorFunction<T, R> {
return function mapOperation(source: Observable<T>): Observable<R> {
if (typeof project !== 'function') {
throw new TypeError('argument is not a function. Are you looking for `mapTo()`?');
}
return source.lift(new MapOperator(project, thisArg));
};
}
So, map() is a function. It is an operator in RxJS terms, yes, but it's still a regular JavaScript function. That's it.
This operator receives projection callback function which gets called by the map operator. This callback is something you're passing to map(), e.g. value => value.id from this example:
source$.pipe(map(value => value.id))
The return value of the map is also a function (declared as OperatorFunction<T, R>). You can tell that it is a function since map returns function mapOperation().
Now, mapOperation function receives only one parameter: source which is of type Observable<T> and returns another (transformed) Observable<R>.
To summarize, when you say:
A Pipeable Operator is a function that takes an Observable as its input and returns another Observable.
This means that an RxJS operator (which is a function) is pipeable when it takes an Observable as its input and returns another Observable which in our case is true: a map operator indeed returns a function (mapOperation) whose signature ((source: Observable<T>): Observable<R>) indicates exactly that: it takes one Observable and returns another.
An operator is a function that takes one observable (the source) as its first argument and returns another observable (the destination, or outer observable)
I already mentioned couple of times that an operator is a just function.
Operators take configuration options, and they return a function that takes a source observable.
Yes, in this case, a map() could be called operator since it receives configuration option - a projecttion callback function. So, there's really no conflicts here since many operators are configurable.
I'd say that there's conflict in this one:
Operators should always return an Observable [..] If you create a method that returns something other than an Observable, it's not an operator, and that's fine.
I guess that this is an old definition when pipeable operators weren't pipeable. Before pipeable operators were introduced (I think in version 5 of RxJS), operators were returning Observables. An old map() implementation indicates just that.
For more information about why creators of RxJS decided to introduce pipeable operators, please take a look at this document.
Another great article about what are Observables can be found here.
Also:
Creation Operators are the other kind of operator, which can be called as standalone functions to create a new Observable.
of() is an example of creation operator which returns (creates) an Observable. Please take a look at the source code.
TL;DR: A map() is a function that usually has one parameter (a projection callback function) which also returns a function that receives a source Observable and returns a destination Observable.
EDIT: To answer your question from comments, I'd like to do it here.
Yes, in RxJS 6 you can create a function that accepts observable and returns another one and that would be the operator. E.g.
function myOperatorFunction(s: Observable<any>) {
return of(typeof s);
}
and you'd call it like
source$.pipe(myOperatorFunction);
Please notice that I didn't call myOperatorFunction in pipe(), I just passed the reference to it, i.e. I didn't write myOperatorFunction with parenthesis, but without them. That is because pipe receives functions.
In cases where you need to pass some data or callback functions, like in map example, you'd have to have another function that would receive your parameters, just like map receives projection parameter, and use it however you like.
Now, you may wonder why there are operators that don't receive any data, but are still created as functions that return function, like refCount(). That is to coincide with other operators that mostly have some parameters so you don't have to remember which ones don't receive parameters or which ones have default parameters (like min()). In case of refCount, if it was written a bit different than it is now, you could write
source$.pipe(refCountOperatorFunction);
instead of
source$.pipe(refCount());
but you'd have to know that you have to write it this way, so that is the reason why functions are used to return functions (that receives observable and returns another observable).
EDIT 2: Now that you know that built in operators return functions, you could call them by passing in source observable. E.g.
map(value => value.toString())(of())
But this is ugly and not recommended way of piping operators, though it would still work. Let's see it in action:
of(1, 2, true, false, {a: 'b'})
.pipe(
map(value => value.toString()),
filter(value => value.endsWith('e'))
).subscribe(value => console.log(value));
can be also written like this:
filter((value: string) => value.endsWith('e'))(map(value => value.toString())(of(1, 2, true, false, {a: 'b'})))
.subscribe(a => console.log(a));
Although this is a completely valid RxJS code, there's no way you can think of what it does when you read the latter example. What pipe actually does here is that it reduces over all the functions that were passed in and calls them by passing the previous source Observable to the current function.
Yes. map itself is an operator.
Every operator returns an Observable so later on you can subscribe to the Observable you created.
Of course when I say 'you created' I mean that you created via a creation operator or using the Observable class: new Observable
A pipeable operator is just an operator that would be inside the pipe utility function.
Any function that returns a function with a signature of Observable can be piped and that's why you can create your own Observables and pipe operators to it.
I am pretty much sure that you already know all of this and all you want to know is why there is a conflict in what you are reading.
First, you don't have to pipe anything to your Observable.
You can create an Observable and subscribe to it and that's it.
Since you do not have to pipe anything to your Observable, what should we do with the operators?
Are they used only within a pipe?
Answer is NO
As mentioned, an operator takes configuration options, in your example:
const squareValues = map((val: number) => val * val);
and then it returns a new function that takes the source Observable so you can later on subscribe to it:
const squaredNums = squareValues(nums);
As we can see, map took (val: number) => val * val and returned a function that now gets the Observable nums: const nums = of(1, 2, 3);
Behind the scenes map will take the source observable and transform according to the configuration.
Now the important thing:
Instead of doing that in this way (which you can but no need for that), it is better to pipe your operators so you can combine all of the functions (assuming you are using more operators) into one single function.
So again, behind the scenes you can refer to pipe as a cooler way to make operations on your source Observable rather then declaring many variables that uses different operators with some configuration which return a function that takes a source Observable.

Does RxJs .first() operator (among others) complete the source observable?

If I have the following code:
const subject = new BehaviorSubject<[]>([]);
const observable = subject.asObservable();
subject.next([{color: 'blue'}])
observable.pipe(first()).subscribe(v => console.log(v))
According to the docs:
If called with no arguments, first emits the first value of the source Observable, then completes....
Does this mean that the source observable(the BehaviorSubject in this case) completes and you can no longer use it? As in you can no longer call .next([...]) on it.
I'm trying to understand how can an observable complete if it doesnt have the .complete() method on it?
I was trying to look at the source code of first() which under the covers uses take() and in turn take() uses lift() so I was curious if somehow first operator returns a copy of the source observable(the subject) and completes that.
The source observable is not completing, what it completes is the subscription. You could have multiple subscriptions on your Observable source, in your case one BehaviorSubject.
subject.next([{color: 'blue'}])
subject.next([{color: 'red'}])
const subs1 = observable.pipe(first()).subscribe(v => console.log(v))
const subs2 = observable.subscribe(v => console.log(v))
In the example above you clearly see that the source is not completing, just the subscription.
I have created a Stackblitz if you want to try it: https://stackblitz.com/edit/rxjs-uv6h6i
Hope I got your point!
Cheers :)

BehaviorSubject map a BehaviorSubject

I have a rxjs#6 BehaviorSubject source$, I want get subvalue from source$
const source$ = new BehaviorSubject(someValue);
const subSource$ = source$.pipe(map(transform));
I expect the subSource$ also is a BehaviorSubject, but is not and How can I get the subSource$ is a BehaviorSubject ?
When a BehaviorSubject is piped it uses an AnonymousSubject, just like a regular Subject does. The ability to call getValue() is therefore not carried down the chain. This was a decision by the community. I agree (as do some others) that it would be nice if the ability to get the value after piping existed, but alas that is not supported.
So you would need to do something like:
const source$ = new BehaviorSubject(value);
const published$ = new BehaviorSubject(value);
const subSource$ = source$.pipe(...operators, multicast(published$));
You could then call getValue() on published$ to retrieve the value after it has passed through your operators.
Note that you would need to either call connect() on the subSource$ (which would make it a "hot" observable) or use refCount().
That said, this isn't really the most rxjs-ish way of doing things. So unless you have a specific reason for dynamically retrieving the value after it passes through your operator vs just subscribing to it in the stream, maybe rethink the approach?

RXjs : How to create an operator on streams : scan operator where the accumulator state can be reset through an observable

I need to create a new instance operator on streams with the following characteristics
Signature
Rx.Observable.prototype.scan_with_reset(accumulator, seed$)
where :
Arguments
accumulator (Function): An accumulator function to be invoked on each element.
seed$ (Observable) : An observable whose values will be used to restart the accumulator function. The accumulator function has the following signature function accumulator_fn(accumulator_state, source_value). I want the value in seed$ to reset accumulator_state to the seed value and emit the seed value.
Returns
(Observable) : An observable sequence which results from the comonadic bind operation (whatever that means, I am copying Rxjs documentation here). Vs. the normal scan operator, what happens here is that when the accumulator function is 'restarted' from the seed value emitted by the seed$ observable, that seed value is emitted, and the next value to be emitted by the scan_with_reset operator will be accumulator_fn(seed, source_value)
Example of use :
var seed$ = Rx.Observable.fromEvent(document, 'keydown')
.map(function(ev){return ev.keyCode})
.startWith(0);
var result$ = counter$.scan_with_reset(seed$,
function accumulator_fn (acc, counter) {return acc+counter});
The following diagrams should explain more in details the expected results:
seed : 0---------13--------27------------
counter : -1--5--2----6---2-----4---1---3---
result : 0-1--6--8-13-19--21-27-31--32--35-
My initial attempt to do this was to modify the accumulator_fn to have the seed$ modify a variable that would in the scope of accumulator_fn so I can detect changes in the function itself.
I pursue two goals here:
have an implementation which is as stateless and closure-less as possible
understand the mechanics behind defining one's own operators on
streams, of which this would be hopefully a simple example
I had a look at scan source code : https://github.com/Reactive-Extensions/RxJS/blob/master/src/core/linq/observable/scan.js
but I am not sure where to go from there.
Does anybody has any experience in creating Rxjs stream operators? What are the conventions to follow and traps to avoid? Are there any examples of custom-made operators that I could look at? How would you go about implementing this particular one?
[UPDATE] : Some test code for the accepted answer
var seed$ = Rx.Observable.fromEvent(document, 'keydown')
.map(function(ev){return ev.keyCode})
.startWith(0);
var counter$ = Rx.Observable.fromEvent(document, 'mousemove')
.map(function(ev){return 1});
var result$ = counter$.scanWithReset(seed$,
function accumulator_fn (acc, counter) {return acc+counter});
var s = function (x) {console.log("value: ", x)};
var disposable = result$.subscribe(s)
Moving the mouse should show a value increase by 1, and pressing a key should restart the counter with the value of the key pressed.
As a general case when creating operators it is generally easiest to use the Observable.create method which essentially defines how your Observable should behave when it is subscribed to or just wrap an existing set of operators ala share.
When you get more into performance there are some other considerations (Observable.create is not terribly efficient at scale) and you could look into creating a custom Observable like map.
For your case I would recommend the former for right now. I would think of your problem really as several independent streams that we would like to flatten into a single stream. Each new stream will start when reset is triggered. This is really sounding an awful lot like flatMap to me:
Rx.Observable.prototype.scanWithReset = function ($reset, accum, seed) {
var source = this;
//Creates a new Observable
return Rx.Observable.create(function (observer) {
//We will be reusing this source so we want to make sure it is shared
var p = source.publish();
var r = $reset
//Make sure the seed is added first
.startWith(seed)
//This will switch to a new sequence with the associated value
//every time $reset fires
.flatMapLatest(function (resetValue) {
//Perform the scan with the latest value
return source.scan(accum, resetValue);
});
//Make sure every thing gets cleaned up
return new Rx.CompositeDisposable(
r.subscribe(observer),
//We are ready to start receiving from our source
p.connect());
});
}

Resources