You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用RxJs的expand配合递归实现分页出现无限循环该如何修复?

问题根因

你遇到的无限循环问题确实来自nextPosition的作用域问题:这个变量是在retreivePagedRecords函数执行初始就计算完成的固定值,同一个函数调用上下文里的expand回调读取到的永远是这个固定值,不会随分页推进更新,自然永远触发不了终止条件。
而且你现在把expand写在递归调用的函数内部,相当于每次请求都会生成新的expand流,逻辑完全混乱了,不需要把RxJS的递归操作符和JS函数递归混在一起用。

修复方案

你可以直接用expand本身的递归能力实现分页,不需要额外写JS递归函数,调整后的代码如下:

private async retreivePagedRecords<T>(
  companyURL: string, 
  query: string, 
  startPosition: number, 
  totalCount: number, 
  transformFn: (qbData: any) => T[]
): Promise<T[]> {
  const headers = this.getHttpConfig();
  // 封装单次获取单页数据的逻辑
  const getPage = (currentPosition: number) => {
    const pageQuery = `${query} STARTPOSITION ${currentPosition} MAXRESULTS ${this.pagingSize}`;
    return this.http.get(`${companyURL}/query?query=${pageQuery}`, headers).pipe(
      map(x => (x as any).data),
      map(transformFn),
      // 把当前页的位置和数据一起返回,给expand判断下一页用
      map(pageData => ({ pageData, currentPosition }))
    );
  };

  const records = await lastValueFrom(
    getPage(startPosition).pipe(
      // expand接收上一次的输出,动态计算下一页的位置
      expand(({ currentPosition }) => {
        const nextPosition = currentPosition + this.pagingSize;
        return nextPosition > totalCount ? [] : getPage(nextPosition);
      }),
      // 只提取返回的数据部分做合并
      map(({ pageData }) => pageData),
      reduce((acc: T[], x: T[]) => acc.concat(x ?? []), []),
      catchError(error => of([]))
    )
  );
  return records;
}

修改点说明

  • 把单页请求逻辑封装成独立的getPage方法,接收当前位置作为入参,每次调用都会生成对应位置的请求
  • 去掉了函数递归逻辑,完全用expand本身的能力处理分页递归,动态计算每次的nextPosition,不会出现固定值的问题
  • 单次请求返回时把当前位置和数据一起传递,确保expand能拿到上一页的真实位置计算下一页偏移

如果你一定要保留原来的函数递归写法,也可以把nextPosition作为入参透传,但完全没必要,上述写法逻辑更清晰,也符合RxJS操作符的设计意图。

内容的提问来源于stack exchange,提问作者link64

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.06 07:36:03