Open myml opened 6 years ago
现有后端接口 /user?uid=1可根据uid查询用户信息,uid可为数组,例如/user?uid=1和/user?uid=1&uid=2&uid=3都是合法查询 在前端封装getUserInfo函数
/user?uid=1
/user?uid=1和/user?uid=1&uid=2&uid=3
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筛选
uid|userinfo|async as user
bufferTime会按时间把值搜集到数据,然后发送
pipe( bufferTime(10), filter(uidList => list.length > 0), switchMap(uidList => getUserInfo(...uidList)), share(), )
当时间段内没有值bufferTime也会发送空数组,所以中间加了筛选。share用来在多个管道之间共享订阅 这样做缺陷是时间间隔不好定,定大了,界面会有一定空白期来等待buffer和接口查询。定小了,浪费cpu
使用scan和debounceTime
pipe( scan((acc, uid) => acc.concat(uid), [] as number[]), debounceTime(10), switchMap(uidList => getUserInfo(...uidList)), share(), )
这样就省去了不停止运行的定时器,也能最低程度的减少界面延迟显示。
上面实现的管道有个bug
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的特性巧妙的解决了。
现有后端接口
/user?uid=1
可根据uid查询用户信息,uid可为数组,例如/user?uid=1和/user?uid=1&uid=2&uid=3
都是合法查询 在前端封装getUserInfo函数为了在angular更方便的使用,创建userinfo管道
前端页面使用
uid|userinfo|async as user
就能在模板使用用户信息 这样做缺陷是会发送多次请求,于是通过rxjs丰富的管道进行缓存,来实现把管道的参数累加到一次查询,然后结果再根据uid筛选初优化:使用bufferTime
bufferTime会按时间把值搜集到数据,然后发送
当时间段内没有值bufferTime也会发送空数组,所以中间加了筛选。share用来在多个管道之间共享订阅 这样做缺陷是时间间隔不好定,定大了,界面会有一定空白期来等待buffer和接口查询。定小了,浪费cpu
二次优化:使用debounceTime
使用scan和debounceTime
这样就省去了不停止运行的定时器,也能最低程度的减少界面延迟显示。
解决BUG:share
上面实现的管道有个bug
把uid传递给buffer,然后等待result结果,再进行筛选。直接next是漏掉第一个uid的原因,此时函数还未返回,result没有订阅者,而share在没有订阅者时,也会断开对底层源Observable的订阅,就这样漏掉了这个数据,第二个管道调用时因为有了第一个管道的订阅,所以管道工作正常。加上setTimeout 0,异步的调用next解决。 第二个bug:scan是连续累计所有值的,单个组件共享同一个管道,当在组件内进行翻页时,查询应该也会包括上一页的uid,这样就会造成多次翻页后,累加过多的uid,造成查询量过大。 实际却并没有发生这种情况,因为share的特性,在翻页时,所有前端页面的管道被清除,share取消订阅,当新页面刷新出现时,管道又被添加,share重新订阅,scan也是一个新的,毕竟share之前是一个冷的 Observables,订阅者有单独的发送者,这个bug就被share的特性巧妙的解决了。