Skip to content

用RxJS把分次查询聚合为批量查询 #18

@myml

Description

@myml

现有后端接口 /user?uid=1可根据uid查询用户信息,uid可为数组,例如/user?uid=1和/user?uid=1&uid=2&uid=3都是合法查询
在前端封装getUserInfo函数

getUserInfo(...uidList: number[]) {
    uidList=Array.from(new Set(uid))
    const params = uidList.reduce(
      (acc, uid) => params.append('uid', uid.toString()),
      new HttpParams(),
    );
    return this.http.get('/user', { params });
}

为了在angular更方便的使用,创建userinfo管道

transform(uid: number) {
  return getUserInfo(uid); 
}

前端页面使用uid|userinfo|async as user就能在模板使用用户信息
这样做缺陷是会发送多次请求,于是通过rxjs丰富的管道进行缓存,来实现把管道的参数累加到一次查询,然后结果再根据uid筛选

初优化:使用bufferTime

bufferTime会按时间把值搜集到数据,然后发送

pipe(
      bufferTime(10),
      filter(uidList => list.length > 0),
      switchMap(uidList => getUserInfo(...uidList)),
      share(),
)

当时间段内没有值bufferTime也会发送空数组,所以中间加了筛选。share用来在多个管道之间共享订阅
这样做缺陷是时间间隔不好定,定大了,界面会有一定空白期来等待buffer和接口查询。定小了,浪费cpu

二次优化:使用debounceTime

使用scan和debounceTime

pipe(
      scan((acc, uid) => acc.concat(uid), [] as number[]),
      debounceTime(10),
      switchMap(uidList => getUserInfo(...uidList)),
      share(),
)

这样就省去了不停止运行的定时器,也能最低程度的减少界面延迟显示。

解决BUG:share

上面实现的管道有个bug

  • 总漏掉第一个管道传递的值
  • 翻页的问题
    两个都与share有关。
    管道函数实现如下
  transform(uid: number) {
    this.buffer.next(uid)
    return this.result.pipe(
      map(infoList => {
        return infoList.find(info => info.uid === uid);
      }),
      first(),
    );
  }

把uid传递给buffer,然后等待result结果,再进行筛选。直接next是漏掉第一个uid的原因,此时函数还未返回,result没有订阅者,而share在没有订阅者时,也会断开对底层源Observable的订阅,就这样漏掉了这个数据,第二个管道调用时因为有了第一个管道的订阅,所以管道工作正常。加上setTimeout 0,异步的调用next解决。
第二个bug:scan是连续累计所有值的,单个组件共享同一个管道,当在组件内进行翻页时,查询应该也会包括上一页的uid,这样就会造成多次翻页后,累加过多的uid,造成查询量过大。
实际却并没有发生这种情况,因为share的特性,在翻页时,所有前端页面的管道被清除,share取消订阅,当新页面刷新出现时,管道又被添加,share重新订阅,scan也是一个新的,毕竟share之前是一个冷的 Observables,订阅者有单独的发送者,这个bug就被share的特性巧妙的解决了。

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions