我已经对导航概念进行了响应建模(用户在前向和后向页面中导航),但是我在使用Reactive Extensions优化它时遇到了麻烦。我确定它是某种缓冲或共享运算符,但是我不太确定它是哪一个或应该推到哪里。
这是我在TypeScript和rxjs中实现的工作的简化示例。
每次用户单击时,我们将其递增一步。 (实际上,这里存在一个网络请求,该请求可能不返回新步骤,或者不返回任何新步骤,因此为什么这不是简单的+ 1
。)
describe('navigate', () => {
it('should increment', () => {
const initial = Observable.of(0);
const plusOne = (ns: Observable<number>) => ns.pipe(map(n => n + 1), tap(x => console.log("Computed", x)));
const clicks = Observable.from([plusOne, plusOne, plusOne]);
const expected = cold("(wxyz|)", { w: 0, x: 1, y: 2, z: 3 });
const result = clicks.pipe(
scan(
(s: Observable<number>, x: (ns: Observable<number>) => Observable<number>) => x(s),
initial),
startWith(initial),
switchAll(),
)
expect(result).toBeObservable(expected);
})
})
它产生正确的输出,并且测试通过。
但是在执行方面,您会在控制台中看到以下内容:
Computed 1
Computed 1
Computed 2
Computed 1
Computed 2
Computed 3
这是有道理的,但是如果plusOne
操作很昂贵(例如,网络请求),则不会每次都从头算起plusOne
。
如何记忆上一个plusOne
的结果,以便以后的plusOne
不需要再次计算整个链?
或者,如果我以错误的方式看待这个问题,该如何解决这个问题?
自从这个问题开始以来,我确实想到了一个解决方案。
const result = clicks.pipe(
scan(
(s: Observable<number>, x: (ns: Observable<number>) => Observable<number>) => x(s).pipe(shareReplay(1)),
initial),
startWith(initial),
switchAll(),
)
其执行方式如下:
Computed 1
Computed 2
Computed 3
但是我认为会导致链条看起来像:
xs.map(x => x + 1).shareReplay(1).map(x => x + 1).shareReplay(1).map(x => x + 1).shareReplay(1)
,而我认为这并不是非常有效(如果每个shareReplay(1)
都缓存一个值)。有更好的方法吗?