可以取消 HttpClient GET 请求吗?
Possible to cancel HttpClient GET request?
我 运行 一个内部 Angular 项目,我想在其中引入一个 "Cancel Request" 按钮。我们有一个带有一堆参数的搜索功能,但这些请求最多可能需要两位数的秒数(10 秒及以上)。通常,当有人在搜索字段中输入过于明确的内容时,就会发生这种情况,因为我们会进行 LIKE/contains 搜索。
我希望能够取消这些请求,因此我的代码在返回到组件时不会执行。这样,我可以快速取消请求并发送新请求。
现在我将按钮设置为禁用,因此用户无法轻松发送新请求。如果我不这样做,就会出现以下问题:
- 发送request_1
- 发送request_2
- request_2 在 3 秒内完成并在页面上显示结果
- request_1 在 10 秒内完成并替换页面上的结果
显然这不是最优的。
要尝试的代码(单击 Get stuff
按钮,出现取消按钮):https://stackblitz.com/edit/angular-cgmyvc
不确定这是否适用于 promises(可能不应该适用),但使用 RxJS 和 Angular 的 HttpClient 就像取消订阅一样简单:
// to send
const requestSubscription = this.httpClient.get(/* ...args */);
// to cancel
requestSubscription.unsubscribe();
为了能够取消请求,您应该首先停止将 observable 转换为 Promise 并改为使用订阅。
您的服务应该是:
export class TestService {
constructor(private http: HttpClient) { }
public GetStuff() {
return this
.http
.get("https://jsonplaceholder.typicode.com/todos/1")
}
}
现在它 returns 是一个 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
按钮,您都会看到请求被取消。
你必须像这样导入它:
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;
}
}
希望这对你有用。
您可以使用 switchMap
运算符,它会自动取消订阅之前的可观察对象。
可以参考这个stackblitz
我 运行 一个内部 Angular 项目,我想在其中引入一个 "Cancel Request" 按钮。我们有一个带有一堆参数的搜索功能,但这些请求最多可能需要两位数的秒数(10 秒及以上)。通常,当有人在搜索字段中输入过于明确的内容时,就会发生这种情况,因为我们会进行 LIKE/contains 搜索。
我希望能够取消这些请求,因此我的代码在返回到组件时不会执行。这样,我可以快速取消请求并发送新请求。
现在我将按钮设置为禁用,因此用户无法轻松发送新请求。如果我不这样做,就会出现以下问题:
- 发送request_1
- 发送request_2
- request_2 在 3 秒内完成并在页面上显示结果
- request_1 在 10 秒内完成并替换页面上的结果
显然这不是最优的。
要尝试的代码(单击 Get stuff
按钮,出现取消按钮):https://stackblitz.com/edit/angular-cgmyvc
不确定这是否适用于 promises(可能不应该适用),但使用 RxJS 和 Angular 的 HttpClient 就像取消订阅一样简单:
// to send
const requestSubscription = this.httpClient.get(/* ...args */);
// to cancel
requestSubscription.unsubscribe();
为了能够取消请求,您应该首先停止将 observable 转换为 Promise 并改为使用订阅。
您的服务应该是:
export class TestService {
constructor(private http: HttpClient) { }
public GetStuff() {
return this
.http
.get("https://jsonplaceholder.typicode.com/todos/1")
}
}
现在它 returns 是一个 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
按钮,您都会看到请求被取消。
你必须像这样导入它:
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;
}
}
希望这对你有用。
您可以使用 switchMap
运算符,它会自动取消订阅之前的可观察对象。
可以参考这个stackblitz