简体   繁体   English

可以取消HttpClient GET请求吗?

[英]Possible to cancel HttpClient GET request?

I run an internal Angular project that I want to introduce a "Cancel Request" button to. 我运行一个内部Angular项目,想向其中引入“取消请求”按钮。 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). 我们有一个带有一堆参数的搜索功能,但是这些请求最多可能需要两位数的秒数(10及以上)。 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 发送请求_1
  2. Send request_2 发送请求_2
  3. request_2 finishes in 3 seconds and shows results on page request_2在3秒内完成,并在页面上显示结果
  4. request_1 finishes in 10 seconds and replaces results on page request_1在10秒内完成并替换页面上的结果

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 要使用的代码(单击Get stuff按钮,然后出现取消按钮): https : //stackblitz.com/edit/angular-cgmyvc

To be able to cancel requests you should firstly stop converting observable into Promise and use subscriptions instead. 为了能够取消请求,您首先应该停止将observable转换为Promise,而是使用订阅。

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 . 如您现在所见,我将订阅放入变量request If it is necessary to cancel request - we just call an unsubscribe method. 如果有必要取消请求-我们只需调用一个unsubscribe方法。 Here is the working stackblitz . 这是工作中的闪电战 I recommend to emulate slow internet via developer tools before testing. 我建议在测试之前通过开发人员工具模拟缓慢的Internet。

You will see that request is canceled each time you press cancel button. 每次按cancel按钮,您都会看到该请求被取消。

You have to import it like this: 您必须像这样导入它:

import { Subscription } from 'rxjs/Subscription';

EDIT Angular 6 编辑角度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. 您可以使用switchMap运算符,该运算符将自动取消订阅先前的可观察对象。

You can refer to this stackblitz 你可以参考这个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: 不确定是否可以通过promises来实现(可能不应该这样做),但是使用RxJS和Angular的HttpClient就像取消订阅一样简单:

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

// to cancel
requestSubscription.unsubscribe();

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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