Rxjs:如果没有结果,请使用更新的参数重试 http 调用

Rxjs : Retry http call with updated parameters if no results

我是 Rxjs 的新手,我正在尝试向我的 API 发出请求,并在参数中传递限制。 我的问题是有时由于某些原因返回的结果是空的。我需要做的是使用更新的参数重试此 API 调用(跳过参数)

pollService.getPoll$(skip, limit).subscribe((pollList) => {        
    doStuff;
},
(error) => {
    doStuff;
});

我阅读了一些关于 RetryWhen RXJS 函数的主题,但它是关于请求失败时的错误,你想重试相同的请求,但我没有错误,我也不知道不想重试相同的请求,我也看到了关于 Replay 函数的主题,但我不是很清楚。

谁能解释一下这里要做什么!!

谢谢

亚历克斯

如果我没理解错的话,您的后端正在使用 skiplimit 参数对数据进行分页。

因此,如果您的 skip 值太高,您希望自动降低它。

在 RxJS 中有很多很多方法可以解决这个问题:

  • 你可以在 getPoll$ 之后插入一个 switchMapSwitchMap 会 return 一个新的 observable,如果可以的话包装结果(使用 of(pollList)),或者 returning pollService.getPoll$(newSkipValue, newLimitValue)
  • 您可以 map 结果并在结果未通过验证时抛出错误。然后你可以 catchError 和 return 新调用 getPoll$
  • 的结果

但是,我建议以不同的方式对调用进行建模。我会使用 Subject 作为请求源,并使用 switchMap 来执行请求。

// inside the component or service
interface GetPollRequest {
  skip: number;
  limit: number;
}

private _callSource = new Subject<GetPollRequest>();

public triggerCall(skip: number, limit: number) {
  this._callSource.next({skip, limit});
}

constructor(...) {
  this._callSource.pipe(
    // every time _callSource emits, we call the server
    switchMap(({skip, limit) => pollService.getPoll$(skip, limit).pipe(
      map(pollList => ({ pollList, skip, limit }))
    ),
    tap(({pollList, skip, limit}) => {
      // update the request in any way you need. You need to make sure
      // that the next automatic trigger doesn't repeat indefinitely,
      // or you'll simulate a DOS attack to your backend
      if (pollList.length < 2) this.triggerCall(skip - 2, limit);
    })
  ).subscribe(pollList => // update the component status);
}

使用此模式,您将主题用作触发器(或自定义事件,它们几乎相同),并在构造函数期间将它们包装起来。

SwitchMap 用于在每次源发出时创建一个可观察对象(在本例中,执行请求)。 Tap 用于执行一个操作(很像订阅),嵌入在管道内的转换链中。

考虑使用 expand 运算符,如下所示:

 import { EMPTY, of } from "rxjs"
 import { expand } from "rxjs/operators"
 public startPolling(skip: number, limit: number): void {
    of([])
       .pipe(
           expand(x => x.length < 2 ? pollService.getPoll$(skip--, limit) : EMPTY)
        )
       .subscribe(pollList => {})
 }

更新:

public poll = (skip: number, limit: number): void => {
  defer(() => getPoll$(1 + skip--, limit))
    .pipe(
      repeat(),
      first(x => {
        if(x.length < 2){
          // update some variable in the component
          return false;
        }

        return true;
      })
    )
    .subscribe(pollList => { })
}