I am trying to understand the observables RxJs and I am using angular framework! I can't understand what is actually happening in 'subscriber function' ,it has a parameter named 'observer', and this parameter has a method in the function body, and its name is next()!can a function parameter own a method? based on which rule?!
and the next question is : what is happening in the 'Observable' class? I think the subscriber function returns or to be more precise, creates and passes a value to the Observable instance! and when we call the subscribe method on 'customIntervalObservable' , it passes that data or value to the subscribe method?
am I right?
const customIntervalObservable = new Observable(function subscriber(
observer
) {
let count = 0;
setInterval(() => {
count++;
observer.next(+count);
if (count > 3) {
observer.error(new Error("count is greater than 3"));
}
}, 1000);
});
this.firstObjSubs = customIntervalObservable.subscribe(
(data: number) => {
console.log(data);
},
(error) => {
console.log(error), alert(error.message);
}
);
}
ngOnDestroy() {
//this.firstObjSubs.unsubscribe();
this.firstObjSubs.unsubscribe();
}
}
Here's a bit more:
You can think of an Observer as something that watches the Observable and reacts to notifications.
What notifications?
Next: When another item is emitted into the Observable
Error: When an error occurs
Complete: When there are no more items to emit
Observer is an object with three functions: one for each type of notification. You can define an Observer in code as shown below. But this is uncommon.
And then pass that Observer object into the subscribe as shown below:
More often, you'll pass either the next callback as shown in the first example below. Or an object with one, two, or three of the callback functions defined as shown in the second example.
The subscribe method tells the Observable stream to start emitting its values. It does not itself emit any values. Think of it as a streaming service, like Disney+ or hulu. You have to first subscribe to the service before you can stream movies.
Does this help?
can a function parameter own a method?
Javascript functions parameters are not typed, so you can pass any value you want - including an object.
what is happening in the 'Observable' class?
I'll give this a try:
An observable is basically just a wrapper around a - subscribe() - function that essentially describes the logic of the observable behaviour.
An observable has the ability to notify subjects - or subscribers, or observers - of changes occuring in its state during its lifecycle. To do so, a contract exists that states that the observable should call a subject next() method. This method should describe the logic for how the subject wants to react to such changes.
When a subject is interested in being notified by an observable of its state changes, it executes the observable subscribe() method, passing itself to it as an argument. This effectively provides the observable the ability to call the subject next() method whenever its logic dictates to do so.
To basically illustrate this in code:
// Function describing the observable logic.
function subscribe(observer){
// Observable logic, including calling observer.next() as many times as the logic dictates to notify the observer of state changes.
}
// Observable wrapper.
let observable = new Observable(subscribe)
// Subject interested in being notified of the observable state changes.
let observer = {
next(value){
// Logic for how to react to notifications from the observable.
}
}
// Effectively execute the observable logic.
observable.subscribe(observer)
For simplicty's sake, I omitted a number of more minor concepts - such as the subject complete() or error() methods, as well as the unsubscribe() function returned by the observable subscribe() function.
Related
To avoid memory leaks in my Angular app i'm using the following well-known pattern to unsubscribe from Observables:
unsubscribe = new Subject();
ngOnInit() {
this.myService.getStuff()
.pipe(takeUntil(this.unsubscribe))
.subscribe(result => {
// processing the result
});
}
ngOnDestroy() {
this.unsubscribe.next();
}
This seemingly works fine, but in some examples i've noticed that complete() is also called on the Subject in addition to next():
ngOnDestroy() {
this.unsubscribe.next();
this.unsubscribe.complete(); // like this
}
Is calling complete() necessary here? If so, why? What are the consequences of not calling complete() in this scenario?
Let's see why you need to unsubscribe first.
Very simplified: Observable instance is holding an array of all subscriptions, which means every callback you have in your subscribe will be held in this array. This is bad news for Component because while it is referred from those functions it cannot be garbage-collected. I talk about these functions:
ngOnInit() {
this.myService.getStuff()
.subscribe(
result => null, // this function will be stored in Observable
error => null, // and this
() => null, // and even this
);
}
and it is applicable to every subscribe call.
Now you add a pipe .pipe(takeUntil(this.unsubscribe)) (or you can e.g. use my small library that does similar but shorter). In fact, your Observable subscribes to the events of Subject. And, whenever it emits a value, the Observable returned by this.myService.getStuff() will complete itself. That means all three functions above will be removed from this Observable's subscriptions array and your component is not referred from there anymore.
Problem solved.
All above you need to understand all the whys you have.
Here we finally come to your question
ngOnDestroy() {
this.unsubscribe.next();
this.unsubscribe.complete();
}
where complete is unnecessary, but not harming as well. Because the only subscriber to this subject was your Observable from this.myService.getStuff() (or other Observables from the same component). That means this Subject will refer to nothing else (the only listener is removed and complete that is supposed to clear all subscriptions is already empty), and as long as only component has reference to the Subject as its property, they both will be collected by garbage collector.
This has been discussed previously eg. here Why a 'next' before 'complete' of Angular takeuntil ngUnsubscribe?
You basically don't have to call complete() because next() will dispose the chain and takeUntil will unsubscribe from this.unsubscribe for you. Only if you had some other logic tied to this.unsubscribe then it might be necessary to call complete().
Anyway, you don't break anything if you do call complete().
in service section of angular.io tutorial for angular2 I hit a method named of.for example :
getHeroes(): Observable<Hero[]> {
return of(HEROES);
}
or in below sample:
getHero(id: number): Observable<Hero> {
// Todo: send the message _after_ fetching the hero
this.messageService.add(`HeroService: fetched hero id=${id}`);
return of(HEROES.find(hero => hero.id === id));
}
in angular.io Just explained
used RxJS of() to return an Observable of mock heroes
(Observable<Hero[]>).
and It was not explained why we should use of operator and exactly what does it do and what are its benefits?
The reason why they're using of() is because it's very easy to use it instead of a real HTTP call.
In a real application you would implement getHeroes() like this for example:
getHeroes(): Observable<Hero[]> {
return this.http.get(`/heroes`);
}
But since you just want to use a mocked response without creating any real backend you can use of() to return a fake response:
const HEROES = [{...}, {...}];
getHeroes(): Observable<Hero[]> {
return of(HEROES);
}
The rest of your application is going to work the same because of() is an Observable and you can later subscribe or chain operators to it just like you were using this.http.get(...).
The only thing that of() does is that it emits its parameters as single emissions immediately on subscription and then sends the complete notification.
Observable.of() is useful for maintaining the Observable data type before implementing an asynchronous interaction (for example, an http request to an API).
As Brandon Miller suggests, Observable.of() returns an Observable which immediately emits whatever values are supplied to of() as parameters, then completes.
This is better than returning static values, as it allows you to write subscribers that can handle the Observable type (which works both synchronously and asynchronously), even before implementing your async process.
//this function works synchronously AND asynchronously
getHeroes(): Observable<Hero[]> {
return Observable.of(HEROES)
//-OR-
return this.http.get('my.api.com/heroes')
.map(res => res.json());
}
//it can be subscribed to in both cases
getHeroes().subscribe(heroes => {
console.log(heroes); // '[hero1,hero2,hero3...]'
}
//DON'T DO THIS
getHeroesBad(): Array<Hero> {
return HEROES //Works synchronously
//-OR-
return this.http.get('my.api.com/heroes') //TypeError, requires refactor
}
In the first example, I assume that the HEROES variable is an array of objects, in which every object corresponds to interface Hero (or is the instance of class Hero). When we call this function somewhere in the code, it will act like this:
heroService.getHeroes()
.subscribe((heroes: Hero[]) => {
console.log(heroes)
// will output array of heroes: [{...}, {...}, ...]
})
It means, that when we use Observable's of creation method with array as argument, on subscription it will emit the whole array, not its' elements one-by-one
In the second example, when we subscribe to Observable, that was returned from getHero() method, it emits only one hero, whose id corresponds to given id.
Basically, when you create Observable with of method and supply arguments to it, on subscription it emits these arguments one-by-one
Here's a good reference
I was going through this blog and reading about Observables and couldn't figure out the difference between the Observable and a Subject.
In stream programming there are two main interfaces: Observable and Observer.
Observable is for the consumer, it can be transformed and subscribed:
observable.map(x => ...).filter(x => ...).subscribe(x => ...)
Observer is the interface which is used to feed an observable source:
observer.next(newItem)
We can create new Observable with an Observer:
var observable = Observable.create(observer => {
observer.next('first');
observer.next('second');
...
});
observable.map(x => ...).filter(x => ...).subscribe(x => ...)
Or, we can use a Subject which implements both the Observable and the Observer interfaces:
var source = new Subject();
source.map(x => ...).filter(x => ...).subscribe(x => ...)
source.next('first')
source.next('second')
Observables are unicast by design and Subjects are multicast by design.
If you look at the below example, each subscription receives the different values as observables developed as unicast by design.
import {Observable} from 'rxjs';
let obs = Observable.create(observer=>{
observer.next(Math.random());
})
obs.subscribe(res=>{
console.log('subscription a :', res); //subscription a :0.2859800202682865
});
obs.subscribe(res=>{
console.log('subscription b :', res); //subscription b :0.694302021731573
});
This could be weird if you are expecting the same values on both the subscription.
We can overcome this issue using Subjects. Subjects is similar to event-emitter and it does not invoke for each subscription. Consider the below example.
import {Subject} from 'rxjs';
let obs = new Subject();
obs.subscribe(res=>{
console.log('subscription a :', res); // subscription a : 0.91767565496093
});
obs.subscribe(res=>{
console.log('subscription b :', res);// subscription b : 0.91767565496093
});
obs.next(Math.random());
Both of the subscriptions got the same output value!
Observables
They are cold: Code gets executed when they have at least a single observer.
Creates copy of data: Observable creates copy of data for each observer.
Uni-directional: Observer can not assign value to observable(origin/master).
The code will run for each observer . If its a HTTP call, it gets called for each observer.
if its a service we want to share among all the components, it wont have latest result all new subscribers will still subscribe to same observable and get value from scratch
Unicast means can emit values from the observable not from any other component.
Subject
They are hot: code gets executed and value gets broadcast even if there is no observer.
Shares data: Same data get shared between all observers.
bi-directional: Observer can assign value to observable(origin/master).
If are using using subject then you miss all the values that are broadcast before creation of observer. So here comes Replay Subject
multicast, can cast values to multiple subscribers and can act as both subscribers and emmitter
I found the accepted answer slightly confusing!
An Observer isn't the interface for feeding an Observable source, it's the interface for observing an Observable source... which makes more sense from the name, right?
So, the reason that:
var observable = Observable.create(observer => {
observer.next('first');
observer.next('second');
...
});
works - creating an observable which emits 'first' then 'second' - is that the argument to Observable.create(...) is a subscribe function, it basically defines which Observer events will happen on a direct Observer of that Observable.
If you want to go into it a little bit further again, it's important to understand that the subscribe function isn't directly called on the Observer object when you subscribe, instead it's mediated by a Subscription object which can enforce correct observable rules, e.g. that an Observable will never emit a new value after observer.complete() has been called, even if your subscribe function looks as if it would.
REF: http://reactivex.io/rxjs/manual/overview.html#creating-observables
A Subject is both an Observable and an Observer and once again it looks just like the Observer interface is the way to 'feed' events to the Subject. But it's easier to understand the naming if you realise that a Subject is a bit like an Observable with the equivalent of the subscribe function (i.e. where you define what events will happen to things observing it) sitting there right on the object, even after it has been created. So, you call Observer methods on the Subject to define what Observer events will happen on things observing it! 😊 (And again, there are intermediate objects involved, to make sure that you can only do legal sequences of things.)
REF: http://reactivex.io/rxjs/manual/overview.html#subject
See rxjs document (more information and examples there):
http://reactivex.io/rxjs/manual/overview.html#subject
What is a Subject? An RxJS Subject is a special type of Observable that allows values to be multicasted to many Observers. While plain Observables are unicast (each subscribed Observer owns an independent execution of the Observable), Subjects are multicast.
A Subject is like an Observable, but can multicast to many Observers. Subjects are like EventEmitters: they maintain a registry of many listeners.
and code, Subject extending Observable: https://github.com/ReactiveX/rxjs/blob/master/src/internal/Subject.ts#L22
/**
* #class Subject<T>
*/
export class Subject<T> extends Observable<T> implements SubscriptionLike {
//...
}
Imagine if you have a stream of data coming into your application like in a websocket connection. You want a way to handle it. There is a few solution:
1. normal ajax request:
This solution is not viable because it is
not applicable to process push data. It is more of a pull then a
push.
2. Promise:
Also not good because you have to trigger them and
they can only retrieve once. Also more of a pull then a push.
So in order to retrieve this data, in the old time, we do a long-polling. Which is where we set an interval function to retrieve that stream of data every 1 minute for an example. Though it works, it actually burdening resources like CPU and memory.
But now with option no 3,
3. Observable: You can subscribe and let the stream of data to come
in non-stop until the function complete has been called.
Cool right ? But then there is another problem. What if you want to observe incoming data only once somewhere in your application. But you want to use that data simultaneously around your application when the data arrived. That is when and where you use Subject.
You place subject.subscribe() at places you want to use throughout your application. When the data arrived, places where there is subject.subscribe() will process them simultaneously. But the observer must subscribe with the subject as its argument like this.
observer.subscribe(subject).
Example application is when you want to build a notification alert.
You cannot have multiple subscription of the same observable because chances are, each subscribers will received different input data. But with subject, all that subscribe() through subject will be retrieving the same data.
Another analogy is through magazine subscription. Each subscribers will received the magazine with their name on it. So, different subscription = different receiver name.(Normal Observable)
But when you share with your friends, all of your friend would receive the same magazine with only your name on it.(Normal Observable with Subject)
This guy explain it very well with code example. You can check it out at https://javascript.tutorialhorizon.com/2017/03/23/rxjs-subject-vs-observable/
Hopefully this answer helps.
Briefly,
subject: you can send to it and receive from it.
Observable: you can receive from it only.
In another words,
In subject you can subscribe to it and you can use it to broadcast to other subscribers any time and anywhere in code.
whilst,
in observable you can subscribe to it only (you can't use it to broadcast data after it have been initialized).
The only place you can broadcast data from observable is inside its constructor.
Observable can inform only one observer, while Subject can inform multiple observers.
From another perspective, it is good to note that the subscription to an Observable re-execute the Observable function. This can lead performance issue if the data source is a service for instance.
If you want several subscribers to get the same value, you may need a Subject.
For this, make sure that your subscription is set before the Subject subscribed to the data source. Otherwise, your process would be stuck.
More details here: https://javascript.tutorialhorizon.com/2017/03/23/rxjs-subject-vs-observable/
Observable:
Only the Observable knows how and when the events are triggered on the observable. i.e the next() method has to be called only inside the instantiated constructor. Also, on subscribing each time, a separate observer is created and calls next() method using particular observer inside constructor only, in the following example subscriber itself is the observer and it is subscribed when the instantiated constructor gets executed.
Ex:
import { Observable } from 'rxjs';
const observable = new Observable(subscriber => {
subscriber.next(1);
subscriber.next(2);
setTimeout(() => {
subscriber.next(3);
}, 1000);
});
Subject:
Here next() method can be used by subject anywhere outside the constructor. Also, when next() method is called before subscribing, the particular event will be missed. Hence next() method has to be called only after subscribing.
Ex:
import { Subject } from 'rxjs';
const subject = new Subject<number>();
subject.next(1); // this is missed
subject.subscribe({
next: (v) => console.log(`observerA: ${v}`)
});
subject.subscribe({
next: (v) => console.log(`observerB: ${v}`)
});
subject.next(2);
I'm attempting to write a custom component that can bind to an observable being passed in through an input and show/hide elements based on the state of the observable. What I'd like to be able to do is something like:
#Input() observable: Observable<any>;
ngOnInit() {
this.observable.onSubscribe(() => {
// show element, run logic on start;
});
this.observable.onCompleteOrNext(() => {
// hide element, run logic on end;
});
}
After pouring over the rxjs documentation, I've found that with let I could do something like:
this.observable.let((o: Observable) => {
// run logic.
return o;
});
But this seems like a bit of a hack, and I also can't figure out how to then run something when the observable completes. I expect the observables to be async, such as an HTTP request, but this component needs to handle it either way.
For the observable completing, I assumed I would be able to do something like the below with the do function:
this.observable.do(() => {
// run logic when observable completes.
// not getting called.
});
But, unless the do function is defined on the observable creation, this is not getting called.
I'm aware Angular2 allows binding the view directly to observables, but I also need the ability to run logic based on the observable, not just show/hide view elements.
My googlefoo is failing me and the rxjs documentation isn't being very enlightening, but I feel like this should be a fairly easy thing to do. Perhaps I am approaching it wrong.
You could provide hook methods within the child component:
export class ChildComponent {
onSubscribe(){}
onNext(){}
onComplete(){}
}
In the parent component, you can use ViewChild to get a reference to the ChildComponent, then subscribe to the observable and call the hook methods at key points:
once you've subscribed
when the observable emits
when the observable completes
.
export class ParentComponent {
#ViewChild('child') child:ChildComponent;
...
this.observable.subscribe(
next => this.child.onNext(),
err => {},
() => this.child.onComplete()
);
this.child.onSubscribe()
}
Live demo
I am using observable in Angular2. As I know so far, each Observable instance come with an observer(1:1), and when we emit something with observer.next(value) we can get that value with observable.subscribe((value) => {}).
var observable = Observable.create(observer => {
observer.next(value);
}
.map(value=>{})
.catch(...)
observable.subscribe(value => {
console.log(value);
})
How can I emit value without knowing the corresponding observer, because I want to emit value outside create function. One possible solution is save observer into some global variable but I think an observable should be enough. Any suggestion for this ??
You're mixing multiple things together. Observables are not in 1:1 relation with Observers (more precisely it's 1:N). If you want to be able to manually emit values you need a Subject which acts as an Observable and an Observer at the same time. Practically this means you can call its next() method and it'll propage the value to all its subscribers (Observers).
For example consider the following code in TypeScript:
import {Subject} from 'rxjs';
let source = new Subject();
source.subscribe(val => console.log('Observer 1:', val));
source.subscribe(val => console.log('Observer 2:', val));
source.next(42);
source.next('test');
This will print to console:
Observer 1: 42
Observer 2: 42
Observer 1: test
Observer 2: test
See live demo: http://plnkr.co/edit/gWMFMnPlLJVDC1pQi8pH?p=preview
Read more:
http://reactivex.io/intro.html
https://github.com/Reactive-Extensions/RxJS#resources
https://github.com/Reactive-Extensions/RxJS/blob/master/doc/gettingstarted/creating.md
Be aware that Observable.create() is a very different animal. It takes as a parameter a function that is called every time a new Observer subscribes. That's why it take the newly subscribed Observer as an argument. In this function you can for example call next() method on the Observer to send it some default value that all subscribes need to receive.
So you probably want to use Subject instead of Observable.create().