如何在JS for循环中检测状态变化?

时间:2020-08-31 06:42:04

标签: javascript react-native

我正在尝试构建一个倒数计时器,其工作方式如下:

const startCountdown = async () => {

   var countdownTime = 10;
   setDisplayTime(countdownTime);

   for (let i = 0; i < 10; i++) {
       
      await sleep(1000);
      countdownTime = countdownTime - 1;
      setDisplayTime(countdownTime);

   }
}

如您所见,该数字从10开始递减(稍后将作为用户输入)。

睡眠功能如下:

const sleep = (ms) => {
    return new Promise((resolve) => setTimeout(resolve, ms));
};

问题是我希望用户能够停止计时器。我最初认为它会像这样工作:

const startCountdown = async () => {

   var countdownTime = 10;
   setDisplayTime(countdownTime);

   for (let i = 0; i < 10; i++) {

      if (timerStopped) {
         
         break;
      
      } else {
       
         await sleep(1000);
         countdownTime = countdownTime - 1;
         setDisplayTime(countdownTime);

   }
}

但是看起来新状态并没有传递到for循环中,它只是记住了函数启动时的状态。

是否有解决此问题的方法?我不需要暂停计时器并重新启动它,只需要将其停止即可(然后可以从那里重置它)。

1 个答案:

答案 0 :(得分:1)

我为您构建了一个rxjs版本...由于可以操纵流,因此我发现此解决方案更容易一些。

const {
  BehaviorSubject,
  timer
} = rxjs

const {
  filter,
  tap,
  withLatestFrom
} = rxjs.operators;

const
  startButton = document.getElementById("startButton"),
  pauseButton = document.getElementById("pauseButton"),
  continueButton = document.getElementById("continueButton"),
  stopButton = document.getElementById("stopButton");

class Timer {

  _time = 0;

  _timerSubscription;

  _paused = new BehaviorSubject(false);

  setTime(time) {
    this._time = time
  }

  start() {
    const step = 1000;
    this._timerSubscription = timer(0, step).pipe(withLatestFrom(this._paused), filter(([v, paused]) => !paused)).subscribe(val => {
      if (this._time <= 0) {
        this.stop();
      }
      console.log(this._time);
      this._time -= step;
    });
  }

  pause() {
    this._paused.next(true)
  }

  continue () {
    this._paused.next(false)
  }

  stop() {
    this.reset();
    if (this._timerSubscription) {
      this._timerSubscription.unsubscribe();
    }
  }

  reset() {
    this._time = 0;
  }
}

const myTimer = new Timer();

myTimer.setTime(10000);

startButton.onclick = () => {
  myTimer.start();
};

pauseButton.onclick = () => {
  myTimer.pause();
}

stopButton.onclick = () => {
  myTimer.stop();
}

continueButton.onclick = () => {
  myTimer.continue();
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.6.2/rxjs.umd.min.js"></script>


<button id="startButton">Start</button>
<button id="stopButton">Stop</button>
<button id="pauseButton">Pause</button>
<button id="continueButton">Continue</button>