假设我有以下事件:
DoSomething
做一些需要一些缓存数据的事情。当我触发事件时,我想查看缓存并对其执行某些操作(如果存在)。如果没有,那么我想获取它,等待它进入缓存,然后重试。
我想出了以下解决方案,但感觉就像我在滥用map
操作员。有没有更合适的操作符来观察流并抛出错误或达到重试的效果?
const DO_SOMETHING = 'DO_SOMETHING';
const FETCH_SOMETHING = 'FETCH_SOMETHING';
const FETCH_SOMETHING_SUCCESSFUL = 'FETCH_SOMETHING_SUCCESSFUL';
const events = new Rx.Subject();
const cache = new Rx.BehaviorSubject(null);
// the magic sauce
const cacheInitializer = cache
// is there a better way than this?
.map(x => {
if (!x) { throw 'empty'; }
return x;
})
.retryWhen(x => {
console.log('Cache is empty');
events.next(FETCH_SOMETHING);
return events.filter(x => x === FETCH_SOMETHING_SUCCESSFUL)
.first();
});
// fake getting the data
events.filter(x => x === FETCH_SOMETHING)
.do(() => { console.log('Fetching data'); })
.delay(1000)
.subscribe(x => {
console.log('Data fetched and put into cache');
cache.next({ data: 1 });
events.next(FETCH_SOMETHING_SUCCESSFUL);
});
// handle doing something
events.filter(x => x === DO_SOMETHING)
.do(() => { console.log('Check the cache'); })
.switchMapTo(cacheInitializer)
.subscribe(x => {
console.log('Do something', x);
});
events.next(DO_SOMETHING);
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.5.6/Rx.min.js"></script>
Context:我正在使用 ngrx 和效果。FETCH_SOMETHING
会触发另一种效果FETCH_SOMETHING_SUCCESSFUL
将表明效果已成功完成。在本例中我的缓存是 ngrx。我认为我不想在 API 层中缓存,因为这仍然会导致我从缓存的响应中更新状态,而不是仅仅依赖于状态中的数据。
你想要一个简单的shareReplay
,但您需要 rxjs 5.5.0 或更高版本,因为有一个错误已修复。
const cached$ = request$.shareReplay(1);
这将在第一次订阅时触发请求,但后续订阅将使用缓存的值。
错误将传递给订阅者,然后销毁内部主题,以便错误本身不会被缓存。这使得可观察的可重试。因此,您可以附加任何您想要的重试逻辑(例如重试直到成功)。
最后,如果 refCount 在某个时刻变为 0,缓存也会持续存在。
shareReplay
还需要第二个参数,很像ReplaySubject
构造函数,定义保留缓存的时间窗口。
// Faked request which sometimes errors
const request$ = Rx.Observable
.defer(() => Rx.Observable.of(Math.random()))
.do(() => console.log('API called'))
.map(val => {
if (val <= 0.3) {
console.log('API error');
throw val;
} else {
return val;
}
})
.delay(250);
const cached$ = request$.shareReplay(1);
Rx.Observable.timer(0, 1000)
.take(5)
.switchMap(() => cached$.retry(5))
.subscribe(console.log);
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.5.6/Rx.min.js"></script>
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)