【问题标题】:Possible to cancel HttpClient GET request?可以取消 HttpClient GET 请求吗?
【发布时间】:2019-09-04 20:36:41
【问题描述】:

我运行一个内部 Angular 项目,我想向该项目引入“取消请求”按钮。我们有一个带有一堆参数的搜索功能,但这些请求最多可能需要两位数的秒数(10 秒及以上)。通常,当有人在搜索字段中输入过于明确的内容时会发生这种情况,因为我们进行了 LIKE/contains 搜索。

我希望能够取消这些请求,因此我的代码在返回到组件时不会执行。这样,我可以快速取消请求并发送新请求。

现在我将按钮设置为禁用,因此用户无法轻松发送新请求。如果我不这样做,就会出现以下问题:

  1. 发送请求_1
  2. 发送请求_2
  3. request_2 在 3 秒内完成并在页面上显示结果
  4. request_1 在 10 秒内完成并替换页面上的结果

显然这不是最优的。

可使用的代码(单击Get stuff 按钮并出现取消按钮):https://stackblitz.com/edit/angular-cgmyvc

【问题讨论】:

    标签: angular angular-httpclient angular8


    【解决方案1】:

    为了能够取消请求,您应该首先停止将 observable 转换为 Promise 并改用订阅。

    你的服务应该是:

    export class TestService {
      constructor(private http: HttpClient) { }
    
      public GetStuff() {
        return this
          .http
          .get("https://jsonplaceholder.typicode.com/todos/1")
      }
    }
    

    现在它返回一个 observable 而不是 promise。

    然后在你的组件中:

    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;
      }
    }
    

    正如您现在看到的,我将订阅放入变量request。如果需要取消请求 - 我们只需调用 unsubscribe 方法。 这是工作的stackblitz。 我建议在测试前通过开发者工具模拟慢速网络。

    每次按下cancel 按钮时,您都会看到请求被取消。

    【讨论】:

      【解决方案2】:

      你必须像这样导入它:

      import { Subscription } from 'rxjs/Subscription';
      

      编辑 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;
        }
      }
      

      希望这对你有用。

      【讨论】:

        【解决方案3】:

        您可以使用 switchMap 运算符自动处理取消订阅以前的 observables。

        你可以参考这个stackblitz

        【讨论】:

        • 工作正常,但与我已有的相比,这看起来非常复杂:O
        • 嗯,在复杂性因素上完全同意你的看法。唯一的优点是随着应用程序的增长,您也可以将流与其他 observable 合并。
        【解决方案4】:

        不确定这对于 Promise 是否可行(可能不应该),但对于 RxJS 和 Angular 的 HttpClient,它就像取消订阅一样简单:

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

        【讨论】:

        • 我很想使用 RxJS 来取消订阅,但我不想重写我的代码,使用对 RxJS 的 Promise :(
        • @MortenMoulder 不能用 vanilla JS promise (AFAIK) 做到这一点,但它可以用 BlueBird 等库。 medium.com/@benlesh/…
        猜你喜欢
        • 2013-08-03
        • 2023-03-06
        • 1970-01-01
        • 1970-01-01
        • 2016-03-08
        • 2016-04-11
        • 2012-01-28
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多