引言
Web
应用,因为组件化大行其道,诞生了一个问题。
如上图所示,顶部导航栏组件需要请求当前登录用户的姓名,左侧菜单栏组件需要请求当前登录用户的菜单权限,根据后台的接口设计,两者都需要在应用初始化时获取当前登录用户。
导航栏发起HTTP
请求,获取当前登录用户信息。
菜单栏发起HTTP
请求,获取当前登录用户信息。
两者请求到的数据是相同的,完全可以共用一个请求来完成这个任务,请求两次无疑耗费网络资源。
但是就这么一个简单的任务,却迭代了好几个实现版本才完美解决。
实现
问题示范
如下所示,多次请求同一接口数据,实际业务场景肯定是跨组件的,这里只是举一个最简单的例子:
export class AppComponent implements OnInit {
constructor(private httpClient: HttpClient) {
}
ngOnInit(): void {
this.getTeachers();
}
getTeachers(): void {
this.request().subscribe((teachers: Array<Teacher>) => {
console.log('request - 1', teachers);
});
this.request().subscribe((teachers: Array<Teacher>) => {
console.log('request - 2', teachers);
});
this.request().subscribe((teachers: Array<Teacher>) => {
console.log('request - 3', teachers);
});
}
request(): Observable<Array<Teacher>> {
return this.httpClient.get<Array<Teacher>>('/assets/mock/teacher.json');
}
}
三个调用方都拿到了数据:
同一个接口,发起了三次HTTP
请求:
初代版本
流程如下:
自定义一个观察者对象,所有要获取当前登录用户的组件要去currentLoginUser$
观察者上进行订阅。
系统初始化时,请求接口数据,将结果next
进观察者对象中。
- 确实解决了多次请求的问题。
- 因为初始化时请求,所以当数据变更时,再订阅到的数据还是旧数据。
- 思维困难,需要实现者深入理解观察者模式。
迭代
最新在StackOverflow
上发现可以采用RxJS share
方式完美地解决该问题,如下所示:
定义一个观察者对象teachers$
,但是这个对象不需要我们自己维护,我们只需要调用httpClient
的方法,将它返回的可观察对象使用share
操作符过滤即可。
之后改造request
方法,返回teachers$
可观察对象。
export class AppComponent implements OnInit {
teachers$: Observable<Array<Teacher>>;
constructor(private httpClient: HttpClient) {
this.teachers$ = this.httpClient.get<Array<Teacher>>('/assets/mock/teacher.json').pipe(share());
}
ngOnInit(): void {
this.getTeachers();
}
getTeachers(): void {
this.request().subscribe((teachers: Array<Teacher>) => {
console.log('request - 1', teachers);
});
this.request().subscribe((teachers: Array<Teacher>) => {
console.log('request - 2', teachers);
});
this.request().subscribe((teachers: Array<Teacher>) => {
console.log('request - 3', teachers);
});
}
request(): Observable<Array<Teacher>> {
return this.teachers$;
}
}
三个调用方都拿到了数据:
同一个接口,只发起了一次HTTP
请求,节省了网络资源:
- 同样实现
HTTP
复用功能。 - 使用方法简单,都是模板代码,即便初学者也可按照范例进行编写。
share
RxJS
相当复杂,这里的share
也只是它的冰山一角。
share
运算符不太好理解,RxJS
相关的概念太多,这里就不一一展开了,请参考文章:译 RxJS: 理解 publish 和 share 操作符
当然,如果你没有足够地时间去学习探究share
运算符,就大胆地使用上述示例代码吧,这,就是最佳实践。
总结
RxJS
基于观察者,但不止于观察者,RxJS
存在着众多的操作符,且都不是那么好理解,太伟大了。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。