简体   繁体   English

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

[英]How to detect state change within JS for loop?

I am trying to build a countdown timer, which works like this:我正在尝试构建一个倒数计时器,其工作方式如下:

const startCountdown = async () => {

   var countdownTime = 10;
   setDisplayTime(countdownTime);

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

   }
}

As you can see, this counts down from 10 (which will be a user input later on).如您所见,这从 10 开始倒计时(稍后将是用户输入)。

The sleep function looks like this:睡眠函数如下所示:

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

The issue is that I want the user to be able to stop the timer.问题是我希望用户能够停止计时器。 I initially thought that it would work like this:我最初认为它会像这样工作:

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);

   }
}

But it doesn't look like the new state is passed into the for loop, it just remembers what the state was when the function started.但是看起来新状态并没有传递到 for 循环中,它只是记住了函数启动时的状态。

Is there a way to work around this?有没有办法解决这个问题? I don't need the timer to be paused and restarted, I just need it to stop (and then I can reset it from there).我不需要暂停和重新启动计时器,我只需要它停止(然后我可以从那里重置它)。

I built a rxjs version for you... I find this solution somewhat easier, because of the ability to manipulate streams.我为你构建了一个 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>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM