I'm trying to respond from a service in my Angular application with the Cached data but also trigger a request to update the when subscribed to. I have tried
cache : Observable<any> = this.http.get<any>(ENDPOINT).pipe(shareReplay(1));
getData() : Observable<any>{
return this.cache;
}
The problem appears to be that the shareReplay blocks further subscriptions. I'm pretty sure I can do this by creating Observables with logic built in but was hoping there may be a streamlined way with the standard operators.
EDIT
The below code provides the desired result, There may be a more elegant way however
cache : ReplaySubject<any> = new ReplaySubject<any>(1);
getData() : Observable<any>{
this.http.get<any>(ENDPOINT).pipe(first()).subscribe(x=>cache.next(x));
return this.cache
}
I think shareReplay more used to prevent repeated requests, you can use ReplaySubject or BehaviorSubject.
---Edit ---
I'm sorry I mistook your intentions, shareReplay should be able to cache data, the only problem is that new requests cannot be regenerated.
Related
I want to be able to call an HTTP endpoint (that I own) from an Azure Function at the end of the Azure Function request.
I do not need to know the result of the request
If there is a problem in the HTTP endpoint that is called I will log it there
I do not want to hold up the return to the client calling the initial Azure Function
Offloading the call of the secondary WebApi onto a background job queue is considered overkill for this requirement
Do I simply call HttpClient.PutAsync without an await?
I realise that the dependencies I have used up until the point that the call is made may well not be available when the call returns. Is there a safe way to check if they are?
My answer may cause some controversy but, you can always start a background task and execute it that way.
For anyone reading this answer, this is far from recommended. The OP has been very clear that they don't care about exceptions or understanding what sort of result the request is returning ...
Task.Run(async () =>
{
using (var httpClient = new HttpClient())
{
await httpClient.PutAsync(...);
}
});
If you want to ensure that the call has fired, it may be worth waiting for a second or two after the call is made to ensure it's actually on it's way.
await Task.Delay(1000);
If you're worried about dependencies in the call, be sure to construct your payload (i.e. serialise it, etc.) external to the Task.Run, basically, minimise any work the background task does.
I have a NestJS application, and need to send an HTTP request to another server, so I am using the HttpModule (#nestjs/axios).
I need the data from that request, but the returned type is <Observable<AxiosResponse<any,any>>, where I need just the AxiosResponse.
Reading over the RxJS documentation, it looks like the prescribed way to handle this situation is to make use of RxJS lastValueFrom() or firstValueFrom(), after the deprecation of toPromise().
However, there is a warning attached:
Only use lastValueFrom function if you know an Observable will eventually complete. The firstValueFrom function should be used if you know an Observable will emit at least one value or will eventually complete. If the source Observable does not complete or emit, you will end up with a Promise that is hung up, and potentially all of the state of an async function hanging out in memory. To avoid this situation, look into adding something like timeout, take, takeWhile, or takeUntil amongst others.
The solution that I came up with was:
const response = this.httpService.post('the-url').pipe(take(1))
const axiosResponse: AxiosResponse = await lastValueFrom(response)
TypeScript at least is not complaining. Is this a suitable way to get at the underlying Axios response?
A promise once triggered will only get resolved or rejected once. Once it's resolved the observable is completed. It is one of the major differences between promise and observable which has capability to emit multiple times like callback.
Therefore there is no need to add pipe(take(1)), just use lastValueFrom is sufficient
If you construct an observable from a promise you don't need lastValueFrom nor take. Once subscribed to, it emits once then completes immediately:
const {from} = rxjs;
const answer$ = from(Promise.resolve(42));
answer$.subscribe({
next(x) {
console.log(`answer=${x}`);
},
complete() {
console.log('done');
}
});
<script src="https://unpkg.com/rxjs#%5E7/dist/bundles/rxjs.umd.min.js"></script>
Should I unsubscribe on every ajax call? According to the RxJS contract, I should. Because AJAX calls are not streams or events, once they are done they are done. What is the reason of using RxJS at all in this particular case? Overtime it becomes the mess (I know about takeUntil, that's not the point here).
public remove(data: IData): void {
// unsubscribe from the previous possible call
if (this.dataSubscription &&
this.dataSubscription.unsubscribe) {
this.dataSubscription.unsubscribe();
}
this.dataSubscription = this.dataService
.delete(data.id)
.subscribe(() => {
this.refresh();
});
}
public ngOnDestroy(): void {
// unsubscribe on deletion
if (this.dataSubscription &&
this.dataSubscription.unsubscribe) {
this.dataSubscription.unsubscribe();
}
}
What is the advantage over simple promise, that looks cleaner and destroyed right after execution?
public remove(data: IData): void {
this.dataService
.delete(data.id)
.then(() => {
this.refresh();
});
}
This is DataService code
#Injectable()
export class DataService {
constructor(private _httpClient: HttpClient) { }
public delete(id: number): Observable<IModel> {
return this._httpClient.delete<IModel>(`${this._entityApiUrl}/${id}`);
}
}
Finite, cold Observables usually don't need to be unsubscribed. They work just like Promises in this regard. Assuming you're using Angular's HttpClient in your service, no unsubscription is necessary--it's much like a Promise in that situation.
First off, to clear some things up -- in your Promise example, you are imperatively managing the Promise by assigning it to this.dataSubscription. After that call is made, anything that calls this.dataSubscription.then() an arbitrary amount of time after the HTTP call will receive a Promise.resolve() and invoke that .then() function. The new Promise returned by Promise.resolve() will be cleaned up after it executes, but it's only until your class is destroyed that your this.dataSubscription Promise will be cleaned up.
However, not assigning that Promise as a property is even cleaner:
public remove(data: IData): void {
this.dataService
.delete(data.id)
.then(() => {
this.refresh();
});
}
plus, the Promise will be cleaned up at the end of its scope, not on the destruction of the class.
Observables, at least finite 'Promise-like' ones like this, work in much the same way. You don't need to manage the Subscription returned buy the .subscribe() method imperitavely, as it will execute and then be cleaned up as it's not assigned as a property:
public remove(data: IData): void {
this.dataService
.delete(data.id)
.subscribe(() => {
this.refresh();
});
}
It's a finite Observable and completes after the subscription, so calling subscribe again will return a new Subscription and re-call the Observable's function.
Imperitavely managing those subscriptions is indeed messy and usually a sign things could be done better.
The difference with RXJS's subscription management is that RXJS can become an incredibly powerful tool, one that is useful for way, way more than managing async AJAX calls. You can have hot Observables that publish data to hundreds of subscribers, Subjects that manage their own stream to many subscribers, infinite Observables that never stop emitting, higher-order Observables that manage state and return other Observables, etc. In this case unsubscribing is best practice, but honestly not going to cause performance issues outside of extreme cases.
A good comparison is the Observable.fromEvent() property. Just like it's best practice to use removeEventListener correctly after addEventListener, you should unsubscribe from this Observable correctly. However, just like removeEventListener,...it's not really done all the time and usually doesn't cause issues with today's platforms.
Also, in reference to the 'RxJS contract' that was stated: here's an excerpt from the same doc:
When an Observable issues an OnError or OnComplete notification to its observers, this ends the subscription. Observers do not need to issue an Unsubscribe notification to end subscriptions that are ended by the Observable in this way.
Finite Observables complete themselves after their emissions and don't need to be unsubscribed.
Usually you don't need to unsubscribe from HttpClient calls since all HttpClient calls complete the stream once they receive response from the server. Once an observable stream completes or errors, its the responsibility of the producer to release resources. For more information, read Insider’s guide into interceptors and HttpClient mechanics in Angular. You should unsubscribe only if you want to cancel the request.
Because AJAX calls are not streams or events, once they are done they are done... What is the advantage over simple promise, that looks cleaner and
destroyed right after execution?
AJAX calls are not just one time event. For example, you can have multiple progress events with XHR. Promise resolves with only one value, while HttpClient can emit multiple HTTP events:
export type HttpEvent<T> =
HttpSentEvent | HttpHeaderResponse | HttpResponse<T>| HttpProgressEvent | HttpUserEvent<T>
You don't need to unsubscribe on every ajax call. But then you are losing one of the core benefits of Observables - being able to cancel it.
You really need to think about what your code does and what is your standard workflow. What happens if the delete response takes a long time and user clicks it again, or clicks back, or goes to some other page?
Would you like refresh to still happen (since observable will still keep the callback in the memory) or would you rather cancel it?
It's up to you and your application at the end. By using unsubscribe you save yourself from unplanned side effects.
In your case, it's just a refresh so it's not a big deal. Then again, you will keep it in the memory and it might cause some side effects.
We've recently picked up Redux Observable and it's been a great way to manage high level action orchestration.
One problem I've recently is responding to the result of a data fetch. We have a generic service function which returns a RXJS observable. Normally we select what ever data we need and subscribe.
I thought this would be fairly natural with redux-observable. Use MapTo on the Epic, and return the RXJS observer with the subsequent select.
From what I can tell Redux-observable doesn't subscribe so nothing happens.
Does anyone have an example of how it should work?
export function redirectUserToEndpointEpic(action$) {
return action$.ofType(LOCATION_CHANGE)
.filter(action=>action.payload.pathname !== '/'))
.mapTo(action=>authService.getObserver() // returns a stream which has not been subscribed to
.select(userData=>userData.defaultPath)
.map(push);
}
This code is actually correct. The dependency was using 'rx' library rather than 'rxjs' which caused a conflict.
Thanks all
I am new to angular and want to use it to send data to my app's backend. In several occasions, I have to make several http post calls that should either all succeed or all fail. This is the scenario that's causing me a headache: given two http post calls, what if one call succeeds, but the other fails? This will lead to inconsistencies in the database. I want to know if there's a way to cancel the succeeding calls if at least one call has failed. Thanks!
Without knowing more about your specific situation I would urge you to use the promise error handling if you are not already doing so. There's only one situation that I know you can cancel a promise that has been sent is by using the timeout option in the $http(look at this SO post), but you can definitely prevent future requests. What happens when you make a $http call is that it returns a promise object(look at $q here). What this does is it returns two methods that you can chain on your $http request called success and failure so it looks like $http.success({...stuff...}).error({...more stuff..}). So if you do have error handling in each of these scenarios and you get a .error, dont make the next call.
You can cancel the next requests in the chain, but the previous ones have already been sent. You need to provide the necessary backend functionality to reverse them.
If every step is dependent on the other and causes changes in your database, it might be better to do the whole process in the backend, triggered by a single "POST" request. I think it is easier to model this process synchronously, and that is easier to do in the server than in the client.
However, if you must do the post requests in the client side, you could define each request step as a separate function, and chain them via then(successCallback, errorCallback) (Nice video example here: https://egghead.io/lessons/angularjs-chained-promises).
In your case, at each step you can check if the previous one failed an take action to reverse it by using the error callback of then:
var firstStep = function(initialData){
return $http.post('/some/url', data).then(function(dataFromServer){
// Do something with the data
return {
dataNeededByNextStep: processedData,
dataNeededToReverseThisStep: moreData
}
});
};
var secondStep = function(dataFromPreviousStep){
return $http.post('/some/other/url', data).then(function(dataFromServer){
// Do something with the data
return {
dataNeededByNextStep: processedData,
dataNeededToReverseThisStep: moreData
}
}, function(){
// On error
reversePreviousStep(dataFromPreviousStep.dataNeededToReverseThisStep);
});
};
var thirdFunction = function(){ ... };
...
firstFunction(initialData).then(secondFunction)
.then(thirdFunction)
...
If any of the steps in the chain fails, it's promise would fail, and next steps will not be executed.