如何以固定间隔在 javascript 中创建计时器?和从数字开始的选项?

How to create timer in javascript with fixed intervals? and option to start from a number?

我正在使用解决方案 创建一个准确的 javascript 计时器。该代码工作正常。但我希望它有一个固定的间隔选项。比如它需要输出 100, 200, 300,等等..,

Math.round(timer.getTime() / 1000); 此代码将值四舍五入到最接近的秒数,因此计时器变为 1、2、3、4、5...

我尝试将 setInterval 的持续时间调整为 50 并四舍五入到最接近的 100,它几乎可以满足我的需要。但它是重复数字,有时会跳过几个数字。

我还需要一些计时器从特定数字开始,比如从 400 到 10000。class 默认为 0。我该如何实施?

更多代码和细节请找代码笔: https://codepen.io/gurgoon32/pen/KKzYYKG

class Timer {
  constructor() {
    this.isRunning = false;
    this.startTime = 0;
    this.overallTime = 0;
  }

  _getTimeElapsedSinceLastStart() {
    if (!this.startTime) {
      return 0;
    }

    return Date.now() - this.startTime;
  }

  start() {
    if (this.isRunning) {
      return console.error('Timer is already running');
    }

    this.isRunning = true;

    this.startTime = Date.now();
  }

  stop() {
    if (!this.isRunning) {
      return console.error('Timer is already stopped');
    }

    this.isRunning = false;

    this.overallTime = this.overallTime + this._getTimeElapsedSinceLastStart();
  }

  reset() {
    this.overallTime = 0;

    if (this.isRunning) {
      this.startTime = Date.now();
      return;
    }

    this.startTime = 0;
  }

  getTime() {
    if (!this.startTime) {
      return 0;
    }

    if (this.isRunning) {
      return this.overallTime + this._getTimeElapsedSinceLastStart();
    }

    return this.overallTime;
  }
}

let the_interval;

function round_nearest_hundred(num) {
  return Math.round(num / 100) * 100;
}

function onUpdateTimer(duration) {
  const timeInSeconds = Math.round(timer.getTime() / 1000);
  document.getElementById('time').innerText = timeInSeconds;

  document.getElementById('accTime').innerText = round_nearest_hundred(timer.getTime());

  console.log(round_nearest_hundred(timer.getTime()));

  if (round_nearest_hundred(timer.getTime()) >= duration) {
    document.getElementById('status').innerText = 'complete';
    timer.stop();
    timer_manager(false);
  }
}

function timer_manager(flag, updateFunction, time, duration) {
  if (flag) {
    the_interval = setInterval(function() {
      updateFunction(duration);
    }, time);
  } else {
    clearInterval(the_interval);
  }
}



const timer = new Timer();
//timer.start();

timer_manager(true, onUpdateTimer, 50, 10000);

document.getElementById('start').addEventListener('click', function() {
  timer.start();
});

document.getElementById('stop').addEventListener('click', function() {
  timer.stop();
});

document.getElementById('restart').addEventListener('click', function() {
  timer_manager(true, onUpdateTimer, 100, 10000);
  timer.reset();
  timer.start();
});
<p>Elapsed time: <span id="time">0</span>s</p>
<p id="accTime"></p>
<p id="status"></p>
<button id="start">start</button>
<button id="stop">pause</button>
<button id="restart">restart</button>

为了提供开始时间值,您只需修改构造函数,使其接受开始时间作为参数:

class Timer {
  constructor (startTime = 0) {
    this.isRunning = false;
    this.startTime = startTime;
    this.overallTime = startTime;
  }
  // ...   
}

const timer1 = new Timer(); // timer1 will start from 0
const timer2 = new Timer(500); // timer2 will start from 500

关于间隔,如果要显示百分之一秒四舍五入到百(例如100,200,300,...),则必须将间隔时间设置为10ms并使用函数“round_nearest_hundred()" 你已经有:

// ...

function onUpdateTimer(duration) {
  //const timeInSeconds = Math.round(timer.getTime() / 1000);
  //document.getElementById('time').innerText = timeInSeconds;
  const timeInHundredthsOfSeconds = round_nearest_hundred(timer.getTime());
  document.getElementById('time').innerText = HundredthsOf;

  document.getElementById('accTime').innerText = round_nearest_hundred(timer.getTime());

  console.log(round_nearest_hundred(timer.getTime()));

  if (round_nearest_hundred(timer.getTime()) >= duration) {
    document.getElementById('status').innerText = 'complete';
    timer.stop();
    timer_manager(false);
  }
}

// ...

timer_manager(true, onUpdateTimer, 10, 10000);

// ...

试一试:

class Timer {
  constructor () {
    this.isRunning = false;
    this.startTime = 0;
    this.overallTime = 0;
  }

  _getTimeElapsedSinceLastStart () {
    if (!this.startTime) {
      return 0;
    }
  
    return Date.now() - this.startTime;
  }

  start () {
    if (this.isRunning) {
      return console.error('Timer is already running');
    }

    this.isRunning = true;

    this.startTime = Date.now();
  }

  stop () {
    if (!this.isRunning) {
      return console.error('Timer is already stopped');
    }

    this.isRunning = false;

    this.overallTime = this.overallTime + this._getTimeElapsedSinceLastStart();
  }

  reset () {
    this.overallTime = 0;

    if (this.isRunning) {
      this.startTime = Date.now();
      return;
    }

    this.startTime = 0;
  }

  getTime () {
    if (!this.startTime) {
      return 0;
    }

    if (this.isRunning) {
      return this.overallTime + this._getTimeElapsedSinceLastStart();
    }

    return this.overallTime;
  }
}

let the_interval;

function round_nearest_hundred(num){
        return Math.floor(num / 100)*100;
}

function onUpdateTimer(start, duration){
  const startTime = timer.getTime() + start;
  const timeInSeconds = Math.floor(timer.getTime() / 1000);
  document.getElementById('time').innerText = timeInSeconds;
  
  document.getElementById('accTime').innerText = round_nearest_hundred(startTime);
  
  console.log(round_nearest_hundred(startTime));
  
  if(round_nearest_hundred(timer.getTime()) >= (duration - start)){
    document.getElementById('status').innerText = 'complete';
    timer.stop();
    timer_manager(false);
  }
}

function timer_manager(flag, updateFunction, time, start, duration){
  if(flag){
    the_interval =  setInterval(function(){updateFunction(start, duration);}, time);
  } else {
    clearInterval(the_interval);
  }   
}



const timer = new Timer();
//timer.start();

timer_manager(true, onUpdateTimer, 50, 1000, 10000);

document.getElementById('start').addEventListener('click', function(){
  timer.start();
});

document.getElementById('stop').addEventListener('click', function(){
  timer.stop();
});

document.getElementById('restart').addEventListener('click', function(){
  timer_manager(false);
  timer_manager(true, onUpdateTimer, 100, 0, 10000);
  timer.reset();
  timer.start();
});
<p>Elapsed time: <span id="time">0</span>s</p>
<p id="accTime"></p>
<p id="status"></p>
<button id="start">start</button>
<button id="stop">pause</button>
<button id="restart">restart</button>

  1. Math.round() 在这种情况下有点令人困惑,因为它意味着 500 毫秒四舍五入为 1 秒,让您认为自己已经达到了那个时间。最好使用 Math.floor()(向下舍入),这样您就只能看到真正经过的秒数。我认为这应该可以解决跳过问题。

  2. Reset函数中,最好在设置新间隔之前清除最后一个间隔。似乎否则你将是 运行 两个 setInterval 函数,只有最新的一个被变量 the_interval.

    引用
  3. 为了从特定数字开始,我向 timer_manager 函数添加了一个参数 (start)。这将传递给 onUpdateTimer 函数,因为这是您的逻辑决定计时器是否已完成的地方(显然,这取决于它从哪个值开始)。最后,同样在该函数中,是否要向用户显示实际经过的秒数(例如开始:1 秒,结束:10 秒,经过:9 秒)还是加上起点(例如开始: 1 秒,结束:10 秒,经过:10 秒)。