[英]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.