-
Notifications
You must be signed in to change notification settings - Fork 1
Description
现有后端接口 /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的特性巧妙的解决了。