简体   繁体   中英

How to cancel ongoing HTTP requests when there's a new requests in angular 6 with rxjs 6

I'm having below RxnsSearchService and RxnsSearchHitCountService , two HTTP services in my app.

handling two requests with forkJoin like below code.

 constructor( private rxnsSearchService: RxnsSearchService, private rxnsSearchHitCountService: RxnsSearchHitCountService ) { } const rxnsObservable: Observable<Array<any>> = this.rxnsSearchService.getReactions(this.searchParams, filters); const headCountObservable: Observable<number> = this.rxnsSearchHitCountService.getHitCount(this.searchParams, filters); forkJoin([rxnsObservable, headCountObservable]).pipe().subscribe((results) => { //handling results }, error => { console.log(error); }); 

I want to cancel the ongoing old requests whenever there is a new request comes. can anyone help me, to make it work around?

 export class RxnsSearchService { sub: Subject<any> = new Subject(); constructor(private httpClient: HttpClient) {} getReactions(params: Params, offset: number, perPage: number, filters: any) { const body = { filters: filters, query: params.query }; return this.httpClient.post(environment.rxnsSearch, body).pipe( map((response: Array<any>) => { return response; }), catchError(error => { console.log(error); return throwError(error); }) ); } } 

 export class RxnsSearchHitCountService { constructor(private httpClient: HttpClient) {} getHitCount(params: Params, filters: any) { const body = { filters: filters, query: params.query, }; return this.httpClient.post(environment.rxnsSearchHitCount, body).pipe( map((response: number) => { return response; }), catchError(error => { console.log(error); return throwError(error); }) ); } } 

I'll go through the general approach of how to do it, with a simplified example. Say we currently have this:

public getReactions() {
  this.http.get(…)
    .subscribe(reactions => this.reactions = reactions);
}

The way to ensure that old requests are cancelled is by instead emitting on some subject:

private reactionsTrigger$ = new Subject<void>();

public getReactions() {
  this.reactionsTrigger$.next();
}

Now we have an observable representing the stream of events triggering a new request. You can now implement OnInit to something like this:

public ngOnInit() {
  this.reactionsTrigger$.pipe(
    // Use this line if you want to load reactions once initially
    // Otherwise, just remove it
    startWith(undefined),

    // We switchMap the trigger stream to the request
    // Due to how switchMap works, if a previous request is still
    // running, it will be cancelled.
    switchMap(() => this.http.get(…)),

    // We have to remember to ensure that we'll unsubscribe from
    // this when the component is destroyed
    takeUntil(this.destroy$),
  ).subscribe(reactions => this.reactions = reactions);
}

// Just in case you're unfamiliar with it, this is how you create
// an observable for when the component is destroyed. This helps
// us to unsubscribe properly in the code above
private destroy$ = new Subject<void>();
public ngOnDestroy() {
  this.destroy$.next();
  this.destroy$.complete();
}

The line

    switchMap(() => this.http.get(…)),

in your case might actually switch the events to the forkJoin :

    switchMap(() => forkJoin([rxnsObservable, headCountObservable])),

if you want a single event stream to trigger both requests anew.

It would be helpful to see a code snippet that shows the actual trigger of the HTTP requests, but it's most likely a UI component that calls a function on click.

The way you would solve this with RxJS 6 is by using a Subject for receiving the click events and then using the switchMap operator to cancel unfinished requests in order to prevent backpressure. Here is an example:

private clickSubject$: Subject<void> = new Subject();

constructor() {
    this.clickSubject$
        .pipe(switchMap(() => forkJoin([rxnsObservable, headCountObservable])))
        .subscribe((results) => // handling)
}

onClick() {
    this.clickSubject$.next(undefined);
}

If you have multiple places where you want to execute the http request, then emit into the subject with: this.clickSubject$.next(undefined) ;

You can simply use the debounce operator in RxJs:

debounce(1000);

its a method provided in to set a delay in milliseconds before sending any request,

The example replaces all the requests fired in 1000ms with only one request.

For further detail:

fromEvent(input, 'input').pipe(
       map((e: any) => e.target.value),
       debounceTime(500),
       distinctUntilChanged()
     ).subscribe(
       (data) => {
           this.onFilterTable({column: fieldName, data});
       }
     );

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM