【问题标题】:setTimeout function in javascript too slow [duplicate]javascript中的setTimeout函数太慢[重复]
【发布时间】:2021-01-22 09:36:21
【问题描述】:

所以我用 JavaScript 和 HTML 为一个项目创建了一个秒表,它只是一个通用秒表,对于 start_timer() 函数,我使用 setTimeout() 函数来确定速度。 但是,当我在浏览器中运行文件时,它们的计数似乎太慢,因为秒数不同步。 这里有视频来说明时钟有多慢:https://drive.google.com/file/d/1mqB4w5ZX7YqW8C57HhgWtIC63eyfKaGe/view?usp=sharing

我觉得这是一个非常愚蠢的问题,但非常感谢;)我想知道我是否需要使用网络工作者或其他东西(这是我的第一个完整的 javascript 项目,所以我对某些东西很陌生) 代码如下

var isTiming = false; //as mentioned in the Design, this is to determine whether the stopwatch IS counting or IS NOT
var speed = 10;  //10 milliseconds count allowing for hundredths of a millisecond for better accuracy
var binaryTrue = 0; //checks to see if the stopwatch is paused
function start_stopwatch() { //function to start the counting
  if (isTiming == true) {
    var stopwatch = document.getElementById("TimeTable").innerHTML; //set the stopwatch to the digital clock in the HTML


    //use of an array to display elapsed time in the format hh:mm:ss:lll
    //each chronological place value is at a different spot in the array from left to right (numeric values)
    var arr = stopwatch.split(":");
    /*splits the array by separating each value (seconds, minutes, etc.) everytime there is a ":"
                                        when a button is pressed */
    var hr = arr[0]; //first position :hr: at the first space of the array
    var min = arr[1]; //seccond position :mm at the second space of the array
    var sec = arr[2]; //third position :ss at the third space of the array
    var millisec = arr[3]; //fourth position :lll at the fourth space of the array


    //Counting up in normal digital clock format, executes every 10 milliseconds which allows for hundredths of a second
    //returns next value after 10 milliseconds are up
    millisec++;
    if (millisec < 10) {
      millisec = "0" + millisec;
    }
    if (millisec / 100 === 1) {
      millisec = 0;
      millisec = "0" + millisec;
      if (sec / 59 === 1) {
        sec = 0;
        sec = "0" + sec; //added in after the place value displayed as "0" and not "00"
        if (min / 59 === 1) {
          hr++;
          min = 0;
          min = "0" + min; //added in after the place value displayed as "0" and not "00"
          sec = 0;
          sec = "0" + sec; //added in after the place value displayed as "0" and not "00"
        } else {
          min++;
          if (min < 10) {
            min = "0" + min;
          }
        }
      } else {
        sec++;
        if (sec < 10) {
          if (sec < 1) {
            sec = "0" + "0" + sec;
          } //added in after it was displayed as "0" not "00"//
          else {
            sec = "0" + sec;
          }
        } else {
          if (sec < 1) {
            sec = "0" + sec;
          }
        }
      }
    }


    //update the HTML digital time
    document.getElementById("TimeTable").innerHTML = hr + ":" + min + ":" + sec + ":" + millisec; //modify the array to the updated time
    setTimeout(start_stopwatch, (speed /* * ((6/7)/1.072)*/ )); //THIS TENDS TO BE OUT OF SYNC AS IT IS SLOWER THAN A NORMAL CLOCK. SO * ((6/7)/1.072) TO IMPROVE SPEED.
    document.getElementById("control").innerHTML = "Pause";
  }
}


//function to allow the user to change the speed of counting as desired, and as many times as they like
//
function change_speed() {
  speedInput = window.prompt("Enter speed, where '1' = 1 second or '2' counts twice as fast, or '0.5' counts slower.");

  //Input validation/verification as the user should only input an actual number, whether a float or an integer.
  //isNaN is a useful function here where NaN means "Not a Number"
  if (isNaN(speedInput)) { //if the value that the user puts in to change the speed into isn't actually (only) a number
    speedInput = window.prompt("Enter speed AS A NUMBER where '1' = 1 second or '2' counts twice as fast, or '0.5' counts slower. Numbers only.");
  }

  speedLength = speedInput.length; //defensive design in the form of input validation - minimum length
  speedInputHolder = speedInput;
  speedInput = 1 / speedInputHolder; //converts speed requested by the USER into counting length (e.g. 2x speed = 0.5 second length, which is 2x faster, so accessible user interface)

  if (speedInput === null) { // "Cancel" button pressed
    speed = speed;
  } else {
    if (speedLength > 0) {
      speedInputInMilliseconds = (speedInput * 10); //not * 1000 as tenth-seconds are included too
      speed = (speedInputInMilliseconds /** ((60/7)/1.072)*/ ); //need to make sure the 4.275 method still syncs*/
    }
  }
  if (speedInputHolder == 1) {
    var indicateSpeed = document.getElementById("speedIndicator").innerHTML = "Counting speed:  " + "(" + (1 / speedInput) + "x speed" + ")";
    var indicateInterval = document.getElementById("FractionalIndicator").innerHTML = "Counting frequency: " + speedInput + " second."
  } else {
    var indicateSpeed = document.getElementById("speedIndicator").innerHTML = "Counting speed:  " + "(" + (1 / speedInput) + "x speed" + ")";
    var indicateInterval = document.getElementById("FractionalIndicator").innerHTML = "Counting frequency: " + speedInput + " seconds."
  }
}

function change_state() { //function to change from start to pause or pause to start
  if (isTiming == false) {
    isTiming = true;
    binaryTrue = 1;
    start_stopwatch();
    var started = document.getElementById("control").innerHTML = "Pause";
    console.log("Timer started.");
  } else {
    stop_stopwatch();
    console.log("Timer stopped.");
  }
}

function reset() {
  if (binaryTrue == 1) {
    var reset = document.getElementById("TimeTable").innerHTML = "00" + ":" + "00" + ":" + "00" + ":" + "00";
    if (isTiming == false) {
      var started = document.getElementById("control").innerHTML = "Start";
    }
    console.log("Timer reset.");
  } else {
    if (binaryTrue == 0) {
      var reset = document.getElementById("TimeTable").innerHTML = "00" + ":" + "00" + ":" + "00" + ":" + "00";
      if (isTiming == false) {
        var started = document.getElementById("control").innerHTML = "Start/Pause";
        console.log("Timer reset.");
      }
    }
  }
}

//Pausing the stop watch, so STOPPING it from continuing counting
//Set the isTiming variable as FALSE which controls the start_timer function from continuing
function stop_stopwatch() {
  isTiming = false;
  document.getElementById("control").innerHTML = "Resume";
  console.log("Timer stopped.");
}


//the same as stop_stopwatch but also RESETS the stopwatch

/* if isTiming is already FALSE and so the timer is paused
change button label into "Start/Pause"
otherwise make isTiming to be FALSE and reset the timer to 00:00:00:00
and reset the label to "start"
(leave the label as "Start/Pause" if the stopwatch isn't used at least once yet so that the user can still see the original instructions")*/
function stop_and_reset_stopwatch() {
  if (binaryTrue == 0) { //if the timer hasn't been used at least once
    if (isTiming == false) {
      document.getElementById("control").innerHTML = "Start/Pause"; //the user won't have knowledge of the instructions yet
    }
  } else {
    isTiming = false;
    document.getElementById("TimeTable").innerHTML = "00" + ":" + "00" + ":" + "00" + ":" + "00";
    if (binaryTrue == 0) { //if the stopwatch HASN'T been used yet at least once, meaning that binaryTrue is still 0
      document.getElementById("control").innerHTML = "Start/Pause";
    } else { //if the stopwatch HAS been used at least once, meaning that binaryTrue is 1
      document.getElementById("control").innerHTML = "Start";
    }
  }
  console.log("Timer stopped and reset.");
}
<link href="https://fonts.googleapis.com/css2?family=Dosis:wght@600&display=swap" rel="stylesheet">
<div class="Stopwatch">
  <div class="SpeedIndicator">
    <div class="IntervalIndicator">
      <div class="CountTable">
        <p><span id="TimeTable" style="color: #00ffbf; font-size: 200px;">00:00:00:00</span></p>
        <div class="Controllers">
          <button id="control" onclick="change_state();">Start/Pause </button>
          <button id="reset" onclick="reset();">Reset </button>
          <button id="stop" onclick="stop_and_reset_stopwatch();">Stop and Reset</button>
          <button id="speed" onclick="change_speed();">Change speed</button>
          <script type="text/javascript" src="timer.js"></script>
          <p><br><span id="Label" style="color: #00ffbf; font-size: 100px; font-weight: bold; font-family: Arial, Helvetica, sans-serif">hr:min:sec:hundredth</span></br>
          </p>
          <heading id="speedIndicator" style="color: #00aba3; font-size: 20px; font-family: Arial">Stopwatch speed: 1 second (default) </heading>
          <br>
          <heading id="FractionalIndicator" style="color: #00aba3; font-size: 10px; font-family: Arial"></heading>
          </br>

【问题讨论】:

  • 坦率地说,我什至不会尝试遵循所有这些代码,但是……setTimeoutsetInterval 根本不保证任何具体的时间安排,不。你不能指望你的代码精确地在毫秒内执行,因为浏览器可能有也可能没有很多其他的事情要做,并且只会尽最大努力执行你的代码。您需要在编写代码时牢记这种期望。
  • 同样可靠的最小超时时间约为10ms。低的一切都不可信。

标签: javascript settimeout stopwatch


【解决方案1】:

setTimeout 保证函数不会早于指定的时间被调用。这是一种非常糟糕的时间测量机制。

一般来说,如果您需要经常更新的内容,您应该改用requestAnimationFrame

无论你是否切换到它,都不要试图数秒。

创建一个日期对象来存储您开始的时间,然后每次执行更新时:将当前时间与开始时间进行比较。

例如:

document.querySelector("button").addEventListener("click", () => {

  const start = moment();

  requestAnimationFrame(function update() {
    const now = moment();
    const duration = moment.duration(now.diff(start));
    document.querySelector('output').value = duration.asSeconds();
    requestAnimationFrame(update);
  });

});
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.0/moment.min.js"></script>

<output>
<button>Start</button>

【讨论】:

  • 其中哪一部分会引用该函数?
猜你喜欢
  • 1970-01-01
  • 2023-03-12
  • 1970-01-01
  • 1970-01-01
  • 2017-04-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-09
相关资源
最近更新 更多