我希望能够从外部 Api 获取特定请求的数据,但是当返回该数据时,还要使其在缓存中可用,以表示应用程序的当前状态。
这个解决方案似乎有效:
var Rx = require('rx');
var cached_todos = new Rx.ReplaySubject(1);
var api = {
refresh_and_get_todos: function() {
var fetch_todos = Rx.Observable.fromCallback($.get('example.com/todos'));
return fetch_todos()
.tap(todos => cached_todos.onNext(todos));
},
current_todos: function() {
return cached_todos;
}
};
但是 - 显然
Subjects
在 Rx 中是不好的做法,因为它们并没有真正遵循函数式响应式(Reactive)编程。以函数式响应式(Reactive)编程方式执行此操作的正确方法是什么?
最佳答案
建议不要使用 Subjects
,因为有一种滥用它们的倾向,就像你所做的那样注入(inject)副作用。它们完全有效地用作将值插入流的方法, 但是 应该严格限制它们的范围,以避免将状态渗入其他代码区域。
这是第一次重构,请注意,您可以预先创建源代码,然后您的 api 代码只是将其包装在一个整洁的小蝴蝶结中:
var api = (function() {
var fetch_todos = Rx.Observable.fromCallback($.get('example.com/todos'))
source = new Rx.Subject(),
cached_todos = source
.flatMapLatest(function() {
return fetch_todos();
})
.replay(null, 1)
.refCount();
return {
refresh: function() {
source.onNext(null);
},
current_todos: function() {
return cached_todos;
}
};
})();
上面的没问题,它维护了您当前的界面,并且包含了副作用和状态,但我们可以做得更好。我们可以创建一个扩展方法或一个接受
Observable
的静态方法。然后我们可以进一步简化为://Executes the function and caches the last result every time source emits
Rx.Observable.withCache = function(fn, count) {
return this.flatMapLatest(function() {
return fn();
})
.replay(null, count || 1)
.refCount();
};
//Later we would use it like so:
var todos = Rx.Observable.fromEvent(/*Button click or whatever*/))
.withCache(
Rx.Observable.fromCallback($.get('example.com/todos')),
1 /*Cache size*/);
todos.subscribe(/*Update state*/);
关于reactive-programming - 如何在没有主题的情况下利用响应式(Reactive)扩展进行缓存?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/31458631/