对于浏览器,SetInterval()对于毫秒来说太多了吗?

时间:2018-06-08 01:31:16

标签: javascript error-handling setinterval

我制作了一个JavaScript秒表,它通过每秒输入一个变量的值来工作(使用setInterval(stopwatchValue, 1000))。我有一些问题:如果用户点击暂停,比如3.8秒,实际的暂停值将是3秒(当他们点击恢复时,秒表将从3.0秒而不是3.8秒继续。)

我有解决方案来解决这个问题。我的想法是通过像setInterval(stopwatchValue, 1)这样的事情每隔一秒更新一次秒表。

我的问题是:浏览器每隔一秒就处理这个代码太多了:

function stopwatchValue("result") {
    document.getElementById("result").innerHTML = timer;
    timer++; 
}

另外:有些人说如果可以,你应该多次避免访问DOM。在我的情况下,如果我用以下代码替换上面的代码,它会工作吗?

var displayResultHere = document.getElementById("result");
function stopwatchValue("result") {
    displayResultHere = timer;
    timer++; 
}

我的秒表:hntr.atwebpages.com/stopwatch/stopwatch.html

3 个答案:

答案 0 :(得分:0)

您需要的是可变延迟。

SetInterval缺乏精确度仍可用于更新用户看到的内容。

有什么不酷的是,舍入效果意味着我可以坐下来快速点击开始和停止反复几个小时,从来没有看到这个东西滴答一秒钟。

你需要做的是点击时间戳,做数学计算以找到实际持续时间(开始时花费的时间),计算应显示的内容,并设置一次(每次开始点击)变量延迟之前SetInterval的一秒钟滴答声再次开始。

这样做,没有任何点击会减慢你的时钟。

答案 1 :(得分:0)

以下是StopWatch的示例。我刚刚做到了。如果您知道如何阅读本网站上必须包含的代码,那么应该很容易理解。



//<![CDATA[
/* external.js */
var doc, bod, htm, M, I, S, Q, StopWatch, old = onload; // for use on other loads
onload = function(){ // load wrapper - not indented to save space
if(old)old(); // change old var name above and here if using technique on other pages
doc = document; bod = doc.body; htm = doc.documentElement;
M = function(tag){
  return doc.createElement(tag);
}
I = function(id){
  return doc.getElementById(id);
}
S = function(selector, within){
  var w = within || doc;
  return w.querySelector(selector);
}
Q = function(selector, within){
  var w = within || doc;
  return w.querySelectorAll(selector);
}
StopWatch = function(outputDiv, decimals, interval){
  var dm = typeof decimals === 'number' ? decimals : 3;
  var iv = typeof interval === 'number' ? interval : 10;
  this.zero = '00:00:0'+(0).toFixed(dm); outputDiv.innerHTML = this.zero;
  var st, si, et;
  this.start = function(){
    if(st === undefined){
      st = Date.now();
    }
    else if(et !== undefined){
      st = Date.now()-et+st; et = undefined;
    }
    si = setInterval(function(){
      var t = Date.now()-st, h = Math.floor(t/3600000), hf = h*3600000, m = Math.floor((t-hf)/60000), mf = m*60000, s = Math.floor((t-hf-mf)/1000), sf = s*1000;
      s = (s+(t-hf-mf-sf)/1000).toFixed(dm);
      if(h.toString().match(/^\d$/))h = '0'+h;
      if(m.toString().match(/^\d$/))m = '0'+m;
      if(s.toString().match(/^\d(\.?\d*)?$/))s = '0'+s;
      var out = h+':'+m+':'+s;
      outputDiv.innerHTML = out;
    }, iv);
    return this;
  }
  this.stop = function(){
    if(si){
      if(et === undefined)et = Date.now();
      clearInterval(si); si = undefined;
    }
    return this;
  }
  this.clear = function(){
    this.stop(); st = et = undefined; outputDiv.innerHTML = this.zero;
    return this;
  }
}
I('f').onsubmit = function(){
  return false;
}
var act = I('act'), clear = I('clear'), out = I('out');
var stopWatch = new StopWatch(out);
act.onclick = function(){
  if(this.value === 'start'){
    stopWatch.start(); this.value = 'stop';
  }
  else{
    stopWatch.stop(); this.value = 'start';
  }
}
clear.onclick = function(){
  stopWatch.clear(); out.innerHTML = stopWatch.zero; act.value = 'start';
}
} // end load
//]]>
&#13;
/* external.css */
html,body{
  padding:0; margin:0;
}
body{
  background:#000; overflow-y:scroll;
}
.main{
  width:940px; background:#ccc; padding:20px; margin:0 auto;
}
#out{
  display:inline-block; width:85px; background:#fff; padding:5px 10px; cursor:default;
}
#act,#clear{
  width:55px; cursor:pointer;
}
&#13;
<!DOCTYPE html>
<html xmlns='http://www.w3.org/1999/xhtml' xml:lang='en' lang='en'>
  <head>
    <meta http-equiv='content-type' content='text/html;charset=utf-8' />
    <meta name='viewport' content='width=device-width' />
    <title>StopWatch</title>
    <link type='text/css' rel='stylesheet' href='external.css' />
    <script type='text/javascript' src='external.js'></script>
  </head>
<body>
  <div class='main'>
    <form id='f' name='f'>
      <div id='out'></div>
      <input id='act' type='button' value='start' />
      <input id='clear' type='button' value='reset' />
    </form>
  </div>
</body>
</html>
&#13;
&#13;
&#13;

答案 2 :(得分:-1)

不使用setTimeout,而是使用requestAnimationFrame()

当计时器启动时,创建一个新的Date,并在每个动画帧中创建一个新日期:减去两个以获得计时器的当前值。

将DOM元素缓存到变量中,就像您已经完成的那样。像这样:

var result_display = document.getElementById("result");
var timer_is_running = false;
var remembered_time = null;
var timer_start_time;

function start_timer() {
  timer_is_running = true;
  timer_start_time = new Date();
  update_timer_value(accumulated_time);
}

function pause_timer() {
  timer_is_running = false;
}

function update_timer_value(acc_time) {
    var elapsed_time = new Date() - timer_start_time;
    if (remembered_time) {
      elapsed_time += remembered_time;
      remembered_time = null;
    }
    var second_value = Math.floor(elapsed_time);
    result_display.innerHTML = second_value;

    if (timer_is_running) {
      requestAnimationFrame(update_timer_value);
    }
    else {
      remembered_time = elapsed_time;
    }
}