I saw an interesting video from 2018 about rxjs and observables
and I was wondering what happened to Observable.forEach
It seems to have been changed quite a lot.
What happened to return type subscription? Now it is a Promise and forEach does not accept
any callback functions for handling errors or completed event?
[
image from https://app.pluralsight.com/library/courses/asynchronous-javascript-rxjs-observables/table-of-contents
Observable.forEach won't emit any next after an error since RxJS 6.3.0.
Observable: forEach will no longer next values after an error (b4bad1f)
You can handle error and complete notifications by then() or catch() because forEach returns a Promise.
range(1, 10).forEach(console.log)
.then(() => console.log('Promise resolved'))
.catch(() => console.log('Promise rejected'));
But yes, there's no way to unsubscribe when using forEach until the source errors or completes.
Related
I have a quick question about observable.
I have the following observable:
getElevation(pos: Cartographic): Observable<Cartographic> {
return new Observable(observer => {
const promise = Cesium.sampleTerrain(this.terrainProvider, 11, Cesium.Cartographic(pos.longitude, pos.latitude))
Cesium.when(promise, (updatedPositions) => {
observer.next(updatedPositions);
observer.complete();
});
});
}
In a component I have:
this.service.getElevation(value).subscribe((e) => {});
My question is, this is a one shoot observable, so I complete just after, is the complete automatically close the subscription? or, do I also have to do this:
const sub = this.service.getElevation(value).subscribe((e) => {sub.unsubscribe();});
In your case you don't need to unsubscribe.
All Observers will automatically be unsubscribed when you call complete. That said, you may want to implement your consuming (component) code do handle the possibility that the implementation of the service may change in the future.
You could do this by using the take operator which will unsubscribe after the first value is emitted:
this.service.getElevation(value).pipe(take(1)).subscribe((e) => {});
You should not unsubscribe in a subscription, it the observable emits instantly then sub is undefined.
If you want a self unsubscribing observable you can use takeUntil
finalise = new Subject();
this.service.getElevation(value).pipe(takeUntil(finalise)).subscribe((e) => {
finalise.next();
finalise.complete();
});
Brief note:
Try to control the subscription with operators such as takeUntil.
You don’t need to unsubscribe yourself if the sender(Subject) completes.
For your case, since the sender returned by getElevation function completes itself after emitting a value one time, you don’t need to either use any operator or unsubscribe yourself to unsubscribe it.
All you have to do: this.service.getElevation(value).subscribe((v) => // do what you want);
I am interested, is there a way to know whether the operator closes a stream or not?
I've been trying to find it in documentation, but with no luck today.
I think you are looking for "complete" callback (or third parameter) of subscribe() method [see the detailing in the comments] -
yourObservable.pipe(
take(1) //or take any number of values i.e. which is a finite number,
map(),
//or some other operators as per your requirement
).subscibe(
//first call back is to handle the emitted value
//this will be called every time a new value is emitted by observable
(value) => {
//do whatever you want to do with value
console.log(value);
},
//second callback is for handling error
//This will be called if an observable throws an exception
//once an exception occurred then also observable complete and no more values recieved by the subscriber
//Either complete callback is called or error callback is called but not
//both
(exception) => {
//do whatever you want to do with error
console.log(error);
},
//third callback will be called only when source observable is complete
//otherwise it will never get called
//This is the place to know if an observable is completed or not
//Once complete callback fires, subscription automatically unsubscribed
() => {
console.log(`Observable is complete and will not emit any new value`)
}
);
see the following stackblitz - https://stackblitz.com/edit/rxjs-toarray-xwvtgk?file=index.ts&devtoolsheight=100
I am calling two method.
complete() returns void observable
getDetails() returns observable
I am calling second one in map.
I wonder if this is correct way or is there any other way?
I called complete() method which updates flag as completed and returns void observable. and I need to call getDetails method which returns observable.
this.dataService.complete(input)
.pipe(
map(() => {this.dataService.getDetails(id)
.subscribe((result) => {
console.log(result);
})
})
).subscribe();
I get result as expected but I am beginner for rxjs.
If this is wrong, please let me know correct way.
Thank you.
You should avoid nested subscribe()
Try use concatMap, mergeMap , switchMap etc to continue the stream
this.dataService.complete(input)
.pipe(
switchMap(() => this.dataService.getDetails(id)),
tap(result=>console.log(result))
).subscribe();
I have an interceptor and I need to chain/execute a promise/observable when the request comes back from the server. How can I do this in rxjs 6?
intercept(): Observable<HttpEvent<any>> {
return next.handle(request)[DO-SOMETHING]
}
If you need to modify the http event:
return next.handle(request).pipe(
mergeMap(request => yourPromiseOrObservable));
What does mergeMap do?
Projects each source value to an Observable which is merged in the output Observable.
And for more help.
If you don't need to modify the http event:
return next.handle(request).pipe(
tap(request => yourPromise.then(_ => ;)));
What does tap do?
Perform a side effect for every emission on the source Observable, but return
an Observable that is identical to the source.
Or, if you need to wait for the promise but don't modify the request:
return next.handle(request).pipe(
delayWhen(request => from(yourPromise)));
What does delayWhen do?
Delays the emission of items from the source Observable by a given time span determined by the emissions of another Observable.
Is there a way to prevent a subscription to a stream (either observable or subject) from completing after calling the error function on the observable/subject?
var subject = new Rx.Subject();
subject.subscribe(function(){alert("OnNext")}, function(){alert("OnError")});
var next = document.querySelector("#next").addEventListener('click', function(){
subject.next();
})
var error = document.querySelector("#error").addEventListener('click', function(){
subject.error();
});
From what I understand, calling subject.error() completes the event stream. So keeping the observable open would break the contract of the Observable object. So how can I handle the lifecycle of the observable in such a way that would recreate the subscription after an error occurs? Here is a plnkr demonstrating the behavior.
Simply said, you can't. At least not with Subjects.
Subjects have internal state and when they emit or receive error notification they mark themself as stopped and will never ever emit anything.
Otherwise, you could use catch() or retry() operators that resubscribe to their source Observable but this wouldn't help you when using Subjects.