如何通过异步操作维护订阅者的顺序



我有一个角度组件,它订阅了它的路由参数。每当路由参数发生变化时,它就会从参数中读取id,并调用一个函数来查找该id的记录。该函数返回一个promise。解析后,组件会为自己设置一个属性,用于数据绑定。

在某些情况下,响应似乎出现了问题,并且设置了错误的值。以下是它的样子:

ngOnInit() {
  this.route.params.subscribe((params) => {
    const id = params['id'];
    console.log('processing', id);
    this.service.getPerson(id).then((person) => {
      console.log('processed id', id);
      this.person = person; // sometimes this happens out of order
    }
  }
}

所以,假设我有一个文本框,我在其中按名称进行筛选,当我键入时,导航事件发生在id获得该名称的第一个结果的地方。有时我会看到:

处理1个

处理2

处理2

已处理1<----问题

解决此问题的最优雅方法是什么?我曾考虑过将承诺转换为可观察的,并试图取消它,但这似乎很严厉。我正试图弄清楚是否有一种方法可以序列化订阅,这样第二个"处理"直到第一个完成才开始。

您需要使用concatMapswitchMapconcatMap将确保在进行下一个请求之前完成对上一个请求的处理。switchMap也将确保订单,但如果在下一个请求到来时仍在处理,则会中止对前一个请求的处理。

ngOnInit() {
  this.route.params.pipe(
      map(params => params['id']),
      tap(id => console.log('processing', id)),
      concatMap(id => fromPromise(this.service.getPerson(id)).pipe(
        tap(person => console.log('processed id', id))
      )), 
      tap(person => this.person = person)
  )
  .subscribe();
}

您可以为每个调用添加一个"request-id",然后返回给您。然后在回调中,您可以检查req-id是否高于上次处理的req-id。

对于具有单个整数响应的小调用来说,这并不理想,但我将我的响应隐藏在标头中,并使用拦截器/过滤器在每次请求时将标头回显给客户端。

最新更新