简单倒计时器 Typescript

16

我在构造函数中有以下代码:

constructor(){
for (let i = 0; i < 90; i++) {
  setTimeout(() => {
    this.counter = this.counter - 1;
  }, 1000)
 }
}

我实际想要的是显示一个倒计时90秒的数字。目前它会立即从90倒数到0。


请注意,目前没有一个令人满意的答案,因为 OP 问题的假设是无效的。正如已经暗示的那样,设置1000毫秒的计时器并不能保证您的函数将在“恰好”1000毫秒后被调用。计时器既不是高分辨率也不是高优先级的。会出现漂移 - 我不得不修复这个确切的代码错误,因为在 CPU 不足的情况下漂移非常明显。您需要获取开始时间并计算剩余时间(例如使用 Date())。只使用间隔来更新显示的频率。 - JackLThornton
4个回答

25

可以使用setInterval代替,使得函数在计数器归零之前每秒被调用一次:

class Timer {
    constructor(public counter = 90) {

        let intervalId = setInterval(() => {
            this.counter = this.counter - 1;
            console.log(this.counter)
            if(this.counter === 0) clearInterval(intervalId)
        }, 1000)
    }
}

或者,如果你想要像for循环一样的效果,并且使用setTimeout,你可以使用async/await和Promises(尽管对于这个简单的例子来说可能有点过头):

function delay(delay: number) {
    return new Promise(r => {
        setTimeout(r, delay);
    })
}
class Timer {
    constructor(public counter = 90) {
        this.doTimer();
    }
    async doTimer() {
        for (let i = 0; i < this.counter; i++) {
            await delay(1000);
            this.counter = this.counter - 1;
            console.log(this.counter);
        }
    }
}

1
我必须等待几分钟,直到我能够 :) - Nicole W.
时间间隔不是1秒。 - Abdullah Nurum
@AbdullahNurum,您是什么意思。1000毫秒=1秒https://www.w3schools.com/jsref/met_win_setinterval.asp。它可能不会精确触发1秒,因为js中的计时器是尽力而为,而不是保证。但应该是1秒。 - Titian Cernicova-Dragomir
@colin,“实例的销毁”是什么意思?JS没有确定性的销毁。只有当没有任何引用指向它时,该实例才会被垃圾回收。只要有一个定时器被调度,该实例就无法被垃圾回收,因此它将在倒计时发生时保持活动状态。 - Titian Cernicova-Dragomir
是的,实际上这就是我的意思。当我的代码不再引用它时,如何使其成为垃圾回收? - colin
显示剩余2条评论

3

我找到的另一种解决方案:

counter: { min: number, sec: number }

  startTimer() {
    this.counter = { min: 30, sec: 0 } // choose whatever you want
    let intervalId = setInterval(() => {
      if (this.counter.sec - 1 == -1) {
        this.counter.min -= 1;
        this.counter.sec = 59
      } 
      else this.counter.sec -= 1
      if (this.counter.min === 0 && this.counter.sec == 0) clearInterval(intervalId)
    }, 1000)
  }

在你的HTML文件中:

<span>{{counter.min}} : {{counter.sec}}</span>

1
这是我的解决方案:
// You can set binding in your templeteurl with this variable that will display the time couner
// for example <span id='myTimeCounter'>{{expirationCounter}}</span>
expirationCounter: string;
startTimer(secsToStart:number): void {
    var start: number = secsToStart;
    var h: number;
    var m: number;
    var s: number;
    var temp: number;
    var timer: any = setInterval(() =>
    {
        h = Math.floor(start / 60 / 60)
        // remove the hours
        temp = start - h * 60 * 60;
        m = Math.floor(temp / 60);
        // remove the minuets
        temp = temp - m * 60;
        // what left is the seconds
        s = temp;

        // add leading zeros for aesthetics
        var hour = h < 10 ? "0" + h : h;
        var minute = m < 10 ? "0" + m : m;
        var second = s < 10 ? "0" + s : s;

        this.expirationCounter = hour + ":" + minute + ":" + second;

        if (start <= 0) {
            // Time elapsed
            clearInterval(timer);
            this.expirationCounter = "Expired";
            // Make here changes in gui when time elapsed
            //....
        }
        start--;
    }, 1000)
}

0

使用 setInterval() 函数,同时计时器以倒序显示,如 10s、9s、8s...

timeLeft: any = 10;

 startTimer() {
    setInterval(() => {
      if (this.timeLeft > 1) {
        this.timeLeft--;
      } else {
        this.timeLeft = 10;
      }
    }, 1000);
  }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接