首页 > 解决方案 > 一系列 HTTP 请求没有按顺序出现。然后可能会在最后一个请求上显示旧请求

问题描述

我使用 Angular 8 创建了我的 Web 应用程序的界面。问题是当我发送多个请求时,它们没有按顺序到达。这会引起很多问题。例如,当用户快速浏览页面时,有时会显示错误的页面。

这是一个使用 HttpClient 检索项目的示例片段:

listOptions = {
  start: 0,
  length: 10
};

private fillCards() {
  this.companyService.getList(this.listOptions).subscribe(res => {
    if (res.code === 1) {
      this.list = res.data; // This list is displayed in the view
    }
  });
}

public pageChange() {
  // Set list parameters
  this.listOptions.start = (this.page - 1) * this.pageSize;
  this.listOptions.length = this.pageSize;

  // Reload the cards
  this.fillCards();
}

公司服务中的列表功能:

constructor(private http: HttpClient, private appSettings: AppSettings) {}

getList(options = new ApiListOptions()) {
  return this.http.post<ApiResponse<CompanyGet[]>>(
    this.appSettings.ApiRoot + 'company/list',
    options
  );
}

标签: angularrxjsobservablehttprequest

解决方案


如果我正确理解您的问题,每次用户导航到下一页时,您都会向后端发出请求以加载该页面。如果他们多次点击下一页按钮,这将导致多个请求被并行触发,最后一个返回“wins”,即显示那些结果。

有很多方法可以解决这个问题。一 - 您可以禁用 UI 中的导航按钮,直到最新请求完成。这样,用户将不得不等到能够再次导航。

同样在 UI 中,您可以为用户提供跳转到特定结果页面的可能性,这样他们就不必点击 5 次即可到达第 5 页。

另一种方法不是在单击时立即触发 http 请求,而是等待一段时间,以查看用户是否仍然单击按钮以到达更远的页面。您将使用debounceTime延迟 http 请求。

有关如何实现此目的,请参见以下示例:https ://angular-s3qpgc.stackblitz.io

您的组件将维护一个“点击队列”,并将任何按钮点击放入其中:

clickQueue = new Subject();
pageNumber = 0;

getDataAsync(): void {
  this.clickQueue.next(this.number++);
}

您将使用 订阅此队列debounceTime(500),以便您仅在用户停止点击 500 毫秒后才采取行动。switchMap运营商确保,如果用户在发送请求后再次开始点击,挂起的 http 调用将被取消(并且其结果被丢弃)

 ngOnInit() {
    this.clickQueue.pipe(
    debounceTime(500),
    switchMap(num => this.callService(num))
  ).subscribe(result => {
    console.log(result);
  });
}

在我的示例中,该callService函数模拟 http 调用,该调用将在 500-1000 毫秒之间的随机时间后返回。

callService(number) {
  return new Observable(subscriber => {
    setTimeout(() => {
    subscriber.next(number);
    subscriber.complete();
    }, 500 + Math.random() * 500);
  });

}

在示例中,您可以看到当您单击“立即获取数据”按钮时会发生什么——这就是您当前的情况。与使用 debounceTime 和 switchMap 的“获取数据异步”相反,这将导致预期的行为。

最后一点:正如其他人所说,每次调用subscribe()Observable 时,都必须unsubscribe稍后再调用,否则会在应用程序中造成内存泄漏和奇怪的错误。这是另一个主题,您可以查看例如这篇文章:https ://blog.angularindepth.com/the-best-way-to-unsubscribe-rxjs-observable-in-the-angular-applications-d8f9aa42f6a0


推荐阅读