Angular 2使用observables

时间:2017-04-13 08:53:12

标签: angular rxjs angular2-services

我发现了许多缓存反应式可观察量的方法,更具体地说,是http请求的结果。但是,由于以下原因,我对提出的解决方案并不完全满意:

1。此答案https://stackoverflow.com/a/36417240/1063354使用私有字段存储第一个请求的结果,并在所有后续调用中重复使用。

代码:

private data: Data;    
getData() {
    if(this.data) {
        return Observable.of(this.data);
    } else {
        ...
    }
}

令人遗憾的是,可观察力的力量完全被忽略了 - 你手动完成了所有的事情。事实上,如果我对将结果分配给局部变量/字段感到满意,我就不会寻找合适的解决方案。 我认为一个不好的做法的另一个重要的事情是服务不应该有一个状态 - 即应该没有包含从一个调用到另一个调用的数据的私有字段。 清除缓存相当容易 - 只需将this.data设置为null,即可重新执行请求。

2。此答案https://stackoverflow.com/a/36413003/1063354建议使用ReplaySubject:

    private dataObs$ = new ReplaySubject(1);

    constructor(private http: Http) { }

    getData(forceRefresh?: boolean) {
        // If the Subject was NOT subscribed before OR if forceRefresh is requested 
        if (!this.dataObs$.observers.length || forceRefresh) {
            this.http.get('http://jsonplaceholder.typicode.com/posts/2').subscribe(
                data => this.dataObs$.next(data),
                error => {
                    this.dataObs$.error(error);
                    // Recreate the Observable as after Error we cannot emit data anymore
                    this.dataObs$ = new ReplaySubject(1);
                }
            );
        }

        return this.dataObs$;
    }

看起来非常棒(再次 - 清除缓存没问题)但我无法映射此调用的结果,即

service.getData().map(data => anotherService.processData(data))

这是因为底层观察者没有调用其完整的方法。我很确定很多反应方法也会在这里工作。要实际获取数据,我必须订阅到此可观察对象,但我不想这样做:我想通过解析器获取我的某个组件的缓存数据< / em>应该返回可观察(或承诺),而不是订阅

路线

{
    path: 'some-path',
    component: SomeComponent,
    resolve: {
      defaultData: DefaultDataResolver
    }
}

解析器

...
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<Data> {
    return this.service.getData();
}

该组件从未激活,因为其依赖性从不已解决。

3。此处https://stackoverflow.com/a/36296015/1063354我找到了使用 publishLast()。refCount()的提案。

代码:

getCustomer() {
    return this.http.get('/someUrl')
        .map(res => res.json()).publishLast().refCount();
}

这满足了我对缓存解析的要求但是我还没有找到一个干净利落的解决方案清除缓存

我错过了什么吗?任何人都可以想出一种更好的方法来缓存反应性可观测量能够映射其结果以及在缓存数据不再相关时刷新它们吗?

3 个答案:

答案 0 :(得分:1)

这个简单的类缓存结果,因此您可以多次订阅.value并只发出1个请求。您还可以使用.reload()发出新请求并发布数据。

您可以像以下一样使用它:

SELECT * FROM subscriptions WHERE device_id=1;
SELECT Value FROM Item1 WHERE Time=(SELECT MAX(Time) FROM Item1);

和来源:

let res = new RestResource(() => this.http.get('inline.bundleo.js'));

res.status.subscribe((loading)=>{
    console.log('STATUS=',loading);
});

res.value.subscribe((value) => {
  console.log('VALUE=', value);
});

答案 1 :(得分:0)

使用选项3.允许清除缓存,您可以将observable分配给私有成员并返回,例如。

getCustomer() {
    if (!this._customers) {
        this._customers = this.http.get('/someUrl')
        .map(res => res.json()).publishLast().refCount();
     }
     return this._customers
}

clearCustomerCache() {
    this._customers = null;
}

答案 2 :(得分:0)

我的缓存方法是将状态保存在reducer / scan fn:

编辑3 :添加了一段代码,通过键盘事件使缓存失效。

编辑2 windowWhen运算符也适用于该任务,并允许以非常简洁的方式表达逻辑:

const Rx = require('rxjs/Rx');
const process = require('process');
const stdin = process.stdin;

// ceremony to have keypress events in node

stdin.setRawMode(true);
stdin.setEncoding('utf8');
stdin.resume();

// split the keypress observable into ctrl-c and c observables.

const keyPressed$ = Rx.Observable.fromEvent(stdin, 'data').share();
const ctrlCPressed$ = keyPressed$.filter(code => code === '\u0003');
const cPressed$ = keyPressed$.filter(code => code === 'c');

ctrlCPressed$.subscribe(() => process.exit());

function asyncOp() {
  return Promise.resolve(Date().toString());
}

const invalidateCache$ = Rx.Observable.interval(5000).merge(cPressed$);
const interval$ = Rx.Observable.interval(1000);

interval$
  .windowWhen(() => invalidateCache$)
  .map(win => win.mergeScan((acc, value) => {
    if (acc === undefined) {
      const promise = asyncOp();
      return Rx.Observable.from(promise);
    }

    return Rx.Observable.of(acc);
  }, undefined))
  .mergeAll()
  .subscribe(console.log);

它只会每5秒执行一次异步选项,并将结果缓存到observable上的其他遗漏。

Sun Apr 16 2017 11:24:53 GMT+0200 (CEST)
Sun Apr 16 2017 11:24:53 GMT+0200 (CEST)
Sun Apr 16 2017 11:24:53 GMT+0200 (CEST)
Sun Apr 16 2017 11:24:53 GMT+0200 (CEST)
Sun Apr 16 2017 11:24:57 GMT+0200 (CEST)
Sun Apr 16 2017 11:24:57 GMT+0200 (CEST)