Javascript 在一段时间内重复使用数据流
假设有一个API可以接受查询并返回结果流,因为某些结果可能会更改Javascript 在一段时间内重复使用数据流,javascript,functional-programming,rxjs,reactive-programming,rxjs5,Javascript,Functional Programming,Rxjs,Reactive Programming,Rxjs5,假设有一个API可以接受查询并返回结果流,因为某些结果可能会更改 type Query = { species?: "dog" | "cat" | "rat", name?: "string", status?: "lost" | "found" } type Result = { species: string, name: string, status: string }[] 假设有多个组件向这个API传递查询,其中一些可能是相同的。人们不想向服务器发送不必要的请求,而是喜
type Query = {
species?: "dog" | "cat" | "rat",
name?: "string",
status?: "lost" | "found"
}
type Result = { species: string, name: string, status: string }[]
假设有多个组件向这个API传递查询,其中一些可能是相同的。人们不想向服务器发送不必要的请求,而是喜欢优化——为了做到这一点,可以包装API并拦截调用
interface ServiceApi {
request(query: Query): Observable<Result>
}
class WrappedServiceApi implements ServiceApi {
constructor(private service: ServiceApi) { }
request(query: Query): Observable<Result> {
// intercepted
return this.service.request(query);
}
}
接口服务API{
请求(查询:查询):可观察
}
类WrappedServiceApi实现ServiceApi{
构造函数(专用服务:ServiceApi){}
请求(查询:查询):可观察{
//拦截
返回此.service.request(查询);
}
}
但如何使用RxJS 5实现此类优化?
围绕RxJS执行此操作可能类似于以下内容:
class WrappedServiceApi implements ServiceApi {
private activeQueries;
constructor(private service: ServiceApi) {
this.activeQueries = new Map<string, Observable<Result>>();
}
request(query: Query): Observable<Result> {
// it's easy to stringify query
const hashed: string = hash(query);
if (this.activeQueries.has(hashed)) {
// reuse existing stream
return this.activeQueries.get(hashed);
} else {
// create multicast stream that remembers last value
const results = this.service.request(query).publishLast();
// store stream for reuse
this.activeQueries.set(hashed, results);
// delete stream 5s after it closed
results.toPromise().then(
() => setTimeout(
() => this.activeQueries.delete(hashed),
5000
)
);
return results;
}
}
}
类WrappedServiceApi实现ServiceApi{
私有查询;
构造函数(专用服务:ServiceApi){
this.activequerys=newmap();
}
请求(查询:查询):可观察{
//将查询字符串化很容易
常量散列:字符串=散列(查询);
if(this.activequerys.has(散列)){
//重用现有流
返回this.activequerys.get(散列);
}否则{
//创建记住最后一个值的多播流
const results=this.service.request(query.publishLast();
//存储流以供重用
this.activequerys.set(散列,结果);
//在流关闭后删除它
results.toPromise()。然后(
()=>设置超时(
()=>this.activequerys.delete(散列),
5000
)
);
返回结果;
}
}
}
可以通过更具声明性的接收方式实现同样的效果吗?我没有测试它,但我会这样做:
request(query: Query): Observable<Result> {
return Observable.of(hash(query))
.flatMap(hashed => {
const activeQueries = this.activeQueries;
if (activeQueries.has(hashed)) {
return activeQueries.get(hashed);
} else {
const obs = this.service.request(query)
.publishReplay(1, 5000)
.refCount()
.take(1);
activeQueries.set(hashed, obs);
return obs;
}
});
}
请求(查询:查询):可观察{
可观察的返回值(散列(查询))
.flatMap(散列=>{
const activequerys=this.activequerys;
if(activequerys.has(散列)){
返回activequerys.get(散列);
}否则{
const obs=this.service.request(查询)
.publishReplay(15000)
.refCount()
.采取(1)项措施;
activequerys.set(散列,obs);
返回obs;
}
});
}
基本上唯一的区别是我在
this.activequerys
中存储可观察到的内容,而不仅仅是它们的结果,然后使用.publishReplay(15000)
将它们缓存5秒钟。这样,当您在5秒后订阅相同的Observable时,它将重新订阅其源Observable。我没有测试它,但我会这样做:
request(query: Query): Observable<Result> {
return Observable.of(hash(query))
.flatMap(hashed => {
const activeQueries = this.activeQueries;
if (activeQueries.has(hashed)) {
return activeQueries.get(hashed);
} else {
const obs = this.service.request(query)
.publishReplay(1, 5000)
.refCount()
.take(1);
activeQueries.set(hashed, obs);
return obs;
}
});
}
请求(查询:查询):可观察{
可观察的返回值(散列(查询))
.flatMap(散列=>{
const activequerys=this.activequerys;
if(activequerys.has(散列)){
返回activequerys.get(散列);
}否则{
const obs=this.service.request(查询)
.publishReplay(15000)
.refCount()
.采取(1)项措施;
activequerys.set(散列,obs);
返回obs;
}
});
}
基本上唯一的区别是我在
this.activequerys
中存储可观察到的内容,而不仅仅是它们的结果,然后使用.publishReplay(15000)
将它们缓存5秒钟。这样,当您在5秒后订阅同一个Observable时,它只会重新订阅其源Observable。除非您执行flatMap,否则它会返回更高阶的流,因此违反了合同。原始示例也在activeQueries中存储了可观测值(不过publishReplay比publishLast更好)。文档链接建议使用Rx.Obervable.defer和stream factory,以确保对API的调用是实际进行的。不过,最好也去掉这个activeQueries映射。没错,应该有flatMap
,除非您使用flatMap,否则它会返回更高阶的流,因此会破坏契约。原始示例也在activeQueries中存储了可观测值(不过publishReplay比publishLast更好)。文档链接建议使用Rx.Obervable.defer和stream factory,以确保对API的调用是实际进行的。不过,最好也去掉这个activeQueries映射。的确,应该有flatMap