Упражнение с реактивным программированием - PullRequest
0 голосов
/ 27 июня 2019

Я изучаю реактивное программирование с помощью RxJS, и у меня есть следующее упражнение:

  • Оно начинается с пустого массива
  • Когда приложение запускается, новый Date ()вставляется в массив
  • Каждый раз, когда вы щелкаете по экрану, в конце массива вводится значение с датой, когда был выполнен щелчок
  • Когда массив имеет 3 значения, выполните вычисления: (array [2] .value () + array [1] .value () - array [0])% 2
  • Если результат = 0, выведите «Result valid»
  • Иначе, ничего.
  • После вычисления массива, если добавлен новый элемент, необходимо удалить первый элемент, переместить остальные и поместить этот новый элемент в конецмассив.

Я пробовал декларативным и реактивным способом, но реактивный способ не убеждает меня в том, что он действительно реактивный, так как он содержит много if / else и много логики в подписчике.

У меня вопрос такой: в функции упражнение_1__v2_reactive, код соответствует реактивному программированию?

function exercise_1__v1_imperative() {
    let values: Array<Date> = [];
    values.push(new Date());

    document.addEventListener(`click`, () => {
        values.push(new Date());
        console.log(`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.log(`result: `, result);

            if (result === 0) {
                console.log(`Resultado valido: `, result);
            }

            values.shift();
        }
    });
}

function exercise_1__v2_reactive() {
    const newDate$ = of(new Date().valueOf());
    // newDate$.subscribe(console.log);

    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.log(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.log(`result: `, result);

            if (result === 0) {
                console.log('Resultado valido: ', result);
            }
        }
    });
}

Ответы [ 2 ]

0 голосов
/ 11 июля 2019

После исследования операторов 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.log('TAPPING: ', val)),
  filter(x => x === 0)
).subscribe(valid => {
  console.log('Result valid')
});

Решение в этом URL: https://stackblitz.com/edit/rxjs-q3aneg

0 голосов
/ 28 июня 2019

Да, ваша функция 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.log),
                    map(values => {
                        const result = (values[2].valueOf() - values[1].valueOf() + values[0].valueOf()) % 2;

                        console.log(`result: `, result);

                        if (result === 0) {
                            return 'Result Valid';
                        }
                        return 'Result Invalid';
                    })
                  ).subscribe(console.log);
}

Обратите внимание, что я не использую startWith, а также отображаю окончательный вариантрезультат с желаемой строкой.Это зависит от того, что вы хотите, чтобы спроектировать окончательный результат.

...