Angular 排队可观察请求

Angular 排队可观察请求,angular,rxjs,observable,Angular,Rxjs,Observable,我有一个服务,经过一些验证后,可以调用我的后端服务器 get(systems?: string[], options?: {}): Observable<System[]> { if ( // cache check ) { // validate options return this.api.get('/systems', options) .map(response => {

我有一个服务,经过一些验证后,可以调用我的后端服务器

get(systems?: string[], options?: {}): Observable<System[]> {
    if (
        // cache check
    ) {
        // validate options
        return this.api.get('/systems', options)
            .map(response => {
                // proccess results, store to cache
            });
    } else {
        return Observable.of(this.systems);
    }
}
get(系统?:字符串[],选项?:{}):可观察{
如果(
//缓存检查
) {
//验证选项
返回此.api.get('/systems',options)
.map(响应=>{
//处理结果,存储到缓存
});
}否则{
(本系统)的可观测返回;
}
}
初始化服务时调用此请求,以获取基本数据(传递选项
{basic:true}
。在我的一个页面上,在组件初始化时调用相同的服务,而不使用基本选项。但是,当站点加载到该页面时,当然会触发两个HTTP请求,因为它们都没有返回并填充缓存


我似乎不知道如何最好地避免这种情况。在理想的解决方案中,请求将排队,我将使用缓存逻辑来确定是否需要另一个HTTP请求,或者我可以返回缓存数据。但是,这种逻辑似乎不符合可观察/观察者模式。我希望得到一些关于如何解决此问题的建议。

为了避免竞争条件,您需要缓存可观测值,而不是直接缓存值

直接缓存值的问题是,您可能会有多个背对背的服务调用,并且您的服务将检查缓存中的值,这些值在您的请求完成之前是不存在的(这会创建争用条件——您的请求与检查缓存的逻辑争用)。您的服务最终将发出多个请求并多次重写相同值的缓存

通过缓存可观察对象,您可以在创建可观察对象后立即将其放在缓存中,并在任何订户需要时返回该可观察对象(无论该可观察对象是否已解析为某个值),这样您就不会发出多个请求

为了简化操作,我们可以缓存对象,它将保留使用
next
调用的最后一个值,并在新订阅者
subscribe
时自动返回该值。这本质上是一个缓存以前的值并将其返回给新订阅者的主题

请参见此简单示例,其中
cache
是一个对象,表示
ReplaySubject
s的缓存:

let cache={};
getCached('key1').subscribe(val=>console.log(“Sub1:,val));//第一个订阅者
getCached('key1').subscribe(val=>console.log(“Sub2:,val));//紧跟在第一个订户之后的第二个订户
函数getCached(键){
if(cache[key])返回cache[key];//缓存的可观察对象是否存在?如果存在,请立即返回它
log(“未缓存。正在获取新值”);
cache[key]=new Rx.ReplaySubject(1);//将cache设置为等于new ReplaySubject
setTimeout(()=>cache[key].next(500),1000);//获取新值并通知我们的ReplaySubject订阅者
返回缓存[key];//立即返回ReplaySubject
}

您可以添加一个缓存服务来集中此类请求,从缓存服务获取它,让它自己处理查询,而不是每次直接调用http。在我上面提到的sudo代码中,缓存正在执行该检查。但即使我先将其发送到其他服务,两个调用都会在任何数据进入缓存之前到达然后发出HTTP请求。我仍然需要以某种方式对请求进行排队。你能解释一下你认为它们会如何避免同时发生吗?谢谢!我考虑过缓存可观察对象本身,但我想不出在进行不同调用时我会如何做;当我不知道将输入哪些参数时,我如何生成密钥?如果y
key
参数丢失,您可以使用默认键,因此类似于
function getCached(key='default'){…}
,您可以设置
cache['default']=defaultReplaySubject
当您的服务被实例化时。如果一个
被传递到
getCached
,那么当我们在缓存上使用括号符号来添加新的键时,该键将被动态地添加到缓存中。在本例中,该键是
'key1'
,但是我们可以使它运行任何其他东西,例如
'domKey'
对不起,我不清楚。正如您在我的服务中所看到的,该方法采用2个参数,这意味着根据参数值,可观察值可能不同,除非我没有正确理解您,这意味着我需要缓存每一个参数。但当它们可能不同时,我如何缓存它们?或者您是说我需要cal中的密钥l?您介意编辑您的问题以包含参数1和参数2的不同值以及该调用的预期缓存值吗?这将帮助我了解您的意思。