Я изучаю реактивное программирование с помощью RxJS, и у меня есть следующее упражнение:
Пробовал с декларативным способом и с реактивным, но реактивный способ не убеждает меня в том, что он действительно реактивный, так как содержит много if/else и много логики в подписчике.
Мой вопрос: В функции training_1__v2_reactive соответствует ли код реактивному программированию?
function exercise_1__v1_imperative() {
let values: Array<Date> = [];
values.push(new Date());
document.addEventListener(`click`, () => {
values.push(new Date());
console.info(`values: `, values);
if (values.length === 3) {
let a = values[0].valueOf(), b = values[1].valueOf(), c = values[2].valueOf();
let result = (c - b + a) % 2;
console.info(`result: `, result);
if (result === 0) {
console.info(`Resultado valido: `, result);
}
values.shift();
}
});
}
function exercise_1__v2_reactive() {
const newDate$ = of(new Date().valueOf());
// newDate$.subscribe(console.info);
const clickDate$ = fromEvent(document, `click`).pipe(
map(x => new Date())
);
clickDate$.pipe(
startWith(new Date()),
scan<Date, Array<Date>>((acc, value) => {
if (acc.length === 3) {
acc.shift();
}
acc.push(value);
return acc;
}, [])
).subscribe(values => {
console.info(values);
if (values.length === 3) {
let a = values[0].valueOf(), b = values[1].valueOf(), c = values[2].valueOf();
let result = (c - b + a) % 2;
console.info(`result: `, result);
if (result === 0) {
console.info('Resultado valido: ', result);
}
}
});
}
@zero298 вопрос обновлен!!



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Да, ваша функция exercise_1__v2_reactive в порядке с точки зрения rxjs с небольшими улучшениями. Вам не нужно использовать startWith и использовать оператор filter только для создания массива длины 3. Я бы предложил следующее:
function exercise_1__v2_reactive() {
fromEvent(document, 'click')
.pipe(
mapTo(new Date()),
scan((acc: any, val) => {
if (acc.length === 3) {
acc.shift();
}
acc.push(val);
return acc;
}, []),
filter(a => a.length === 3),
//Tap is just to check what my array is - But its not needed
tap(console.info),
map(values => {
const result = (values[2].valueOf() - values[1].valueOf() + values[0].valueOf()) % 2;
console.info(`result: `, result);
if (result === 0) {
return 'Result Valid';
}
return 'Result Invalid';
})
).subscribe(console.info);
}
Обратите внимание, что я не использую startWith, а также сопоставляю окончательный результат с желаемой строкой. Это зависит от того, что вы хотите спроецировать на конечный результат.
Интересный ответ. У меня вопрос по скану: может другого оператора можно? Я думал об использовании буферов, может ли это сработать?
@Marlonchosky Я сомневаюсь, что операторы буфера могут быть здесь полезны, потому что операторы буфера выдают буферизованные элементы в соответствии с условием буфера. Хотя вы можете использовать его, но в конечном итоге вы получите императивный код внутри вашего конвейера оператора или подпишитесь. Задача состоит в том, чтобы отследить последние две даты. Я думаю, что scan оператор - ваш лучший друг здесь.
Спасибо за ответ. Да, я думал, что с буферами я мог бы испускать каждый раз, когда у меня есть 3 даты, но тогда проблема была бы в том, как сохранить последние 2 даты
После изучения операторов RxJS решение можно выполнить с помощью оператора bufferCount, передав его в качестве параметров bufferCount(3, 1), второй параметр указывает, когда запускать новый буфер, что в данном случае будет выполняться при каждом нажатии:
fromEvent(document, 'click').pipe(
map(_ => new Date()),
startWith(new Date()),
bufferCount(3, 1),
map(([a, b, c]) => (c.valueOf() - b.valueOf() + a.valueOf()) % 2),
tap(val => console.info('TAPPING: ', val)),
filter(x => x === 0)
).subscribe(valid => {
console.info('Result valid')
});
Решение находится в этом URL: https://stackblitz.com/edit/rxjs-q3aneg
Я не понимаю, в чем твой вопрос.