假设有一个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);
}
}
但是如何使用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;
}
}
}
可以用更多声明性的rx-way实现同样的目标吗?
答案 0 :(得分:0)
我没有测试过,但是我这样做了:
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;
}
});
}
基本上唯一的区别是我在this.activeQueries
中存储了Observable而不仅仅是他们的结果,然后我使用.publishReplay(1, 5000)
将它们缓存5秒。这样,当您在5s之后订阅相同的Observable时,它只会重新订阅其源Observable。