我希望能够从外部 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/

10-12 06:29