简体   繁体   中英

Possible to cancel HttpClient GET request?

I run an internal Angular project that I want to introduce a "Cancel Request" button to. We have a search function that takes a bunch of parameters, but these requests can take up to two digit amount of seconds (10 and above). Usually that happens when someone types something too explicit into the search field, because we do a LIKE/contains search.

I want to be able to cancel these requests, so my code doesn't execute when returned to the component. That way, I can quickly cancel the request and send a new one.

Right now I set the button to disabled, so the user can't easily send a new request. If I don't do that, the following problem happens:

  1. Send request_1
  2. Send request_2
  3. request_2 finishes in 3 seconds and shows results on page
  4. request_1 finishes in 10 seconds and replaces results on page

Obviously that's not optimal.

Code to play around with (click the Get stuff button and a cancel button appears): https://stackblitz.com/edit/angular-cgmyvc

To be able to cancel requests you should firstly stop converting observable into Promise and use subscriptions instead.

Your service should be:

export class TestService {
  constructor(private http: HttpClient) { }

  public GetStuff() {
    return this
      .http
      .get("https://jsonplaceholder.typicode.com/todos/1")
  }
}

Now it returns an observable instead of promise.

Then in your component:

export class AppComponent  {
  constructor(private service: TestService){}
  public request;
  public Result;
  public GettingStuff = false;

  async ngOnInit() {

  }

  public GetStuff() {
    this.GettingStuff = true;
    this.request = this.service.GetStuff().subscribe((res) => {
      this.Result = JSON.stringify(res);
      this.GettingStuff = false;
    })
  }

  public async CancelGettingStuff() {
    console.log('cancelled');
    this.request.unsubscribe();
    this.GettingStuff = false;
  }
}

As you see now I put the subscription into a variable request . If it is necessary to cancel request - we just call an unsubscribe method. Here is the working stackblitz . I recommend to emulate slow internet via developer tools before testing.

You will see that request is canceled each time you press cancel button.

You have to import it like this:

import { Subscription } from 'rxjs/Subscription';

EDIT Angular 6

import { Subscription } from 'rxjs';



import { Component } from '@angular/core';
import { TestService } from './services/test-service';
import { Subscription } from 'rxjs';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent  {
  constructor(private service: TestService){}
  public Result;
  public GettingStuff = false;
    res: Subscription;
  async ngOnInit() {

  }

  public async GetStuff() {
    this.GettingStuff = true;

     this.res = await this.service.GetStuff(); 
    console.log(this.res);
    this.Result = JSON.stringify(this.res);

    this.GettingStuff = false;
  }

  public async CancelGettingStuff() {
    this.res.unsubscribe();
    this.GettingStuff = false;
  }
}

Hope this works for you .

You can use switchMap operator which automatically takes care of unsubscribing from previous observables.

You can refer to this stackblitz

Not sure if that's doable with promises (probably shouldn't be), but with RxJS and Angular's HttpClient it's as simple as unsubscribing:

// to send
const requestSubscription = this.httpClient.get(/* ...args */);

// to cancel
requestSubscription.unsubscribe();

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