【问题标题】:Performing multiple Http requests to same endpoint, merge and sort response对同一端点执行多个 Http 请求,合并和排序响应
【发布时间】:2019-08-03 01:05:55
【问题描述】:

我想要实现的是向 api 发出多个请求,合并和排序结果并将其分配给 this.products$ observable。这主要是因为代码现在看起来(见下文),最终结果最终变成了一个列表。

fetchIds() 方法从存储中获取参数。 sliceToArrays(any[], number) 接收参数列表并将其拆分为更小的部分。我这样做的原因是为了避免 GET 方法 this.api.listProducts([],'') 的 url 太长,因为 url 查询有一个最大字符限制,当有太多 Id 时会受到影响.

我面临的问题是,除了我以错误的方式使用它的痛苦感觉之外,我无法让它对合并的结果进行排序;它对 2 个列表进行排序,然后再组合它们,使其看起来像这样 [A, B, C, A, B, C] 而不是 [A, A, B, B, C, C]。

ngOnInit() {
this.pageSize = 100;

this.products$ = this.fetchIds().pipe(
  mergeMap(ids =>
    forkJoin(this.sliceToArrays(ids, this.pageSize).map(idsList => this.api.listProducts(idsList, 'watchlist'))).pipe(
      mergeMap(products => merge(...products)),
      toArray(),
      map(products => sortBy(products, ['inventoryStatus', 'authorLastFirst']))
))); }

sliceToArrays(input: any[], maxSliceSize: number): any[][] {
const slices = Math.floor((input.length + maxSliceSize - 1) / maxSliceSize);
const collection: any[][] = [];
for (let i = 1; i <= slices; i++) {
  collection.push(input.slice((i - 1) * maxSliceSize, i * maxSliceSize));
}
return collection; }

fetchSkus() {
return this.watchListStore.items.pipe(
  filter(watchlist => watchlist !== null),
  map(watchlist => watchlist.map(i => i.id))
); }

谁能指出我正确的方向?这几天我一直在尝试不同的东西,但这(角度、打字稿等)并不是我真正的专业领域。

【问题讨论】:

  • 为什么要在客户端做这一切?为什么不在服务器上?
  • 我想主要原因是方便和灵活。已经存在用于在后端通过 id 获取产品的良好、灵活的框架,并且简单地将前端从进行 1 次调用更改为进行 X 次调用似乎比在服务器上的控制器中为这种特定用途创建一个全新的方法要好。跨度>

标签: angular typescript rxjs angular6 angular-httpclient


【解决方案1】:

我不能让它对合并的结果进行排序;它对 2 个列表进行排序,然后再组合它们,使其看起来像这样 [A, B, C, A, B, C] 而不是 [A, A, B, B, C, C]。

我认为您可以稍微扁平化您的信息流。另外,不要忘记错误处理。也许是这样的:

this.products$ = this.fetchids().pipe(
  map(ids => this.sliceToArrays(ids, this.pageSize)),
  switchMap(idLists => combineLatest(...idsList.map(ids => this.api.listProducts(ids, 'watchlist')))),
  map(productLists => productLists.reduce((acc, curr) => ([...acc, ...curr]), [])),
  map(products => products.sort((a, b) => a.inventoryStatus.localCompare(b.inventoryStatus))),
  catchError(error => of([])) // and a nice message to the UI
)

当逻辑像这里这样不平凡时,我喜欢制作一个人类可读的层,并在函数中隐藏 hacky 逻辑:

this.products$ = this.fetchids().pipe(
  map(ids => splitIdsIntoQueriableChunks(ids, this.pageSize)),
  switchMap(idLists => fetchAllProducts(idLists)),
  map(productLists => mergeProducts(productLists)),
  map(products => sortProducts(products)),
  catchError(error => notifyError(error))
)

【讨论】:

  • 谢谢,我认为它可以解决。被压扁!案例是这样的:我用 fetchIds() 得到了一个 ID 列表。我想使用这些 ID 来获取产品列表并将其添加到 this.products$,它是一个 Observable。由于 Id 列表可能太长而无法在单个 GET 调用中使用(带有查询参数的 url 中有 2086 个字符的限制),我想将列表拆分为多个较小的列表(列表的确切数量在 sliceToArrays()) 中进行计算,然后对每个列表发出 GET 请求,将响应合并到一个列表中并按字母顺序对其进行排序。
  • @TomasHjelm 我编辑了我的答案,我不确定 combineAll 那样好。如果您有任何问题,请随时联系我。
  • 天啊,我太傻了。它确实有效,我忘了我先按“inventoryStatus”排序,然后按字母顺序排序,所以它应该看起来像 [A,B,C,A,B,C],只有第一个 ABC 可用,另一个不可用。 ..感谢您的帮助!你的解决方案看起来更干净,是的,当我知道它有效时,我现在会让它更好地可读=)
猜你喜欢
  • 2021-10-31
  • 1970-01-01
  • 1970-01-01
  • 2020-01-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-10-09
  • 1970-01-01
相关资源
最近更新 更多