首页 > 解决方案 > 根据反应式编程启动和停止计数器

问题描述

我有两个按钮,一个按钮初始化计数器,另一个按钮停止计数器。在声明式编程之后,我根据命令式编程实现了一个函数,并用 observables 实现了另一个函数。

但是,我对声明式的代码并不满意,因为它有副作用和全局参数。

有没有办法根据功能反应式编程来实现这个功能而没有副作用和全局参数?

function exercise_pause_play_observable__imperative() {
    const btnStart = document.querySelector('#btnStart');
    const btnStop = document.querySelector('#btnStop');
    const timer1 = document.querySelector('#timer1') as HTMLDivElement;

    let isEnabled = false;
    let cant = 0;
    let int1: number;
    btnStart.addEventListener('click', () => {
        if (!isEnabled) {
            isEnabled = true;
            int1 = setInterval(() => {
                cant++;
                timer1.textContent = cant.toString();
            }, 1000)
        }

    });
    btnStop.addEventListener('click', () => {
        isEnabled = false;
        clearInterval(int1);
    });
}

function exercise_pause_play_observable__declarative()  {
    const btnStart = document.querySelector('#btnStart');
    const btnStop = document.querySelector('#btnStop');
    const timer1 = document.querySelector('#timer1') as HTMLDivElement;

    let isEnabled = false;
    let cant = 0;
    let int1: number;

    const clickStart$ = fromEvent(btnStart, 'click').pipe(
        tap(e => {
            if (!isEnabled) {
                isEnabled = true;
                int1 = setInterval(() => {
                    cant++;
                    timer1.textContent = cant.toString();
                }, 1000);
            }
        })
    );
    const clickStop$ = fromEvent(btnStop, 'click').pipe(
        tap(e => {
            isEnabled = false;
            clearInterval(int1);
        })
    );

    merge(clickStart$, clickStop$);
}

HTML

<body>
    <button id="btnStart">START</button>
    <button id="btnStop">STOP</button>
    <div id="timer1"></div>


    <script src="/bundle.js"></script>
</body>

标签: javascriptrxjsreactive-programming

解决方案


使用一个被称为 stop$ 的主题与 takeUntil 取消的间隔。

const { Subject, fromEvent, interval } = rxjs;
const { takeUntil } = rxjs.operators;

const stop$ = new Subject();

fromEvent(document.getElementById('btnStart'), 'click').subscribe(() => {
  stop$.next(); // If restarting make sure the old one is cancelled
  const timerDiv = document.getElementById('timer1');
  timerDiv.innerText = '';
  interval(1000).pipe(takeUntil(stop$)).subscribe(val => {
    timerDiv.innerText = (val + 1);
  });
});

fromEvent(document.getElementById('btnStop'), 'click').subscribe(() => {
  stop$.next();
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.5.2/rxjs.umd.min.js"></script>

<button id="btnStart">START</button>
<button id="btnStop">STOP</button>
<div id="timer1"></div>


推荐阅读