Я смоделировал концепцию навигации реактивно (пользователь перемещается вперед и назад по страницам), но у меня возникли проблемы с оптимизацией с помощью 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)
кэширует значение). Есть ли лучший способ сделать это?