程序中的JavaScript计时器以不可预测的方式停止

时间:2017-01-12 23:44:10

标签: javascript

我是一个完全初学者,我在空闲时间编写代码。任何人都可以解释我,为什么有时我的番茄钟时钟会在0 0 1(小时,分钟,秒)时卡住

我可以在chrome中的一个选项卡中启动它,它将在不可预测的循环数量下工作,然后在下一个循环开始之前无理由停止在0 0 1。我希望它连续工作(工作,休息,工作,休息等),直到我点击重置按钮...

有没有更好的方法来处理JS中的时间?

代码:

// Code wrapped in a closure to avoid global variables
(function () {
  let countdown;
  let timeIsRunnig = false;
  let actionTypeSwitch = "Work";

  const timerDisplay = document.querySelector(".display__time-left");
  const infoDisplay = document.querySelector(".display__info");
  const endTime = document.querySelector(".display__end-time");
  const buttons = document.querySelectorAll("[data-time]");
  const breakSettings = document.querySelectorAll(".settings__breakButton");
  const workSettings = document.querySelectorAll(".settings__workButton");
  const breakValue = document.querySelector("#valueBreak");
  const workValue = document.querySelector("#valueWork");
  const buttonMain = document.querySelector("#buttonMain");

  let workValueSettings = 25; // Default work session value in min
  let breakValueSettings = 5; // Default break session value in min

  workValue.textContent = workValueSettings + ' min';
  breakValue.textContent = breakValueSettings + ' min';

  timerDisplay.textContent = `${ workValueSettings}:00`;
  infoDisplay.textContent = "Are you ready?";
  endTime.textContent = "Press START";

  function timer(seconds) {
    // Clear any existing timers
    clearInterval(countdown);
    // Current time in ms
    const now = Date.now();
    const future = now + seconds * 1000;
    displayTimeLeft(seconds);
    displayEndTime(future);

    function timeCalc() {
      const secondsLeft = Math.round((future - Date.now()) / 1000);
      // Check if we should stop it
      if (secondsLeft < 0) {
        clearInterval(countdown);
        return;
      }
      // Display it
      displayTimeLeft(secondsLeft);
    }
    countdown = setInterval(timeCalc, 1000);
  }

  function startTimer() {
    const seconds = workValueSettings * 60;
    actionTypeSwitch = "Work";
    infoDisplay.textContent = "Working hard!";
    timer(seconds);
  }

  function startBreak() {
    const seconds = breakValueSettings * 60;
    actionTypeSwitch = "Break";
    infoDisplay.textContent = "Short break!";
    timer(seconds);
  }

  function resetTimer() {
    const seconds = workValueSettings * 60;
    // Clear any existing timers
    clearInterval(countdown);
    // Refresh display
    displayTimeLeft(seconds);
    infoDisplay.textContent = "Are you ready?";
    endTime.textContent = "Press START";
  }

  function startAndReset() {
    let name = "START";
    if (timeIsRunnig === false) {
      timeIsRunnig = true;
      name = "RESET";
      this.innerHTML = name;
      startTimer();
    } else {
      timeIsRunnig = false;
      name = "START";
      this.innerHTML = name;
      resetTimer();
    }
  }

  function playSoundStartBreak() {
    // Returns the first Element within the document
    // that matches the specified group of selectors.
    const audio = document.querySelector(`audio[data-sound="workDone"]`);
    if(!audio) return; // Stop the function from running
    audio.currentTime = 0; // Rewind to the start
    audio.play();
  }

  function playSoundBackToWork() {
    // Returns the first Element within the document
    // that matches the specified group of selectors.
    const audio = document.querySelector(`audio[data-sound="backToWork"]`);
    if(!audio) return; // Stop the function from running
    audio.currentTime = 0; // Rewind to the start
    audio.play();
  }

  function displayTimeLeft(sec) {
    const hours = parseFloat(Math.floor(sec / 3600));
    const minutes = parseFloat(Math.floor(sec / 60));
    const remainderMinutes = parseFloat(minutes % 60);
    const remainderSeconds = parseFloat(sec % 60);
    console.log(hours, remainderMinutes, remainderSeconds);

    // Play sound when timer gets to 0
    if (parseFloat(sec) === 0) {
      if (actionTypeSwitch === "Work") {
        playSoundStartBreak()
        startBreak();
      } else {
        playSoundBackToWork();
        startTimer();
      }
    }

    // Hide hours when hours is 0
    let hoursFirstStatement = hours < 10 ? "0" : "";
    let hoursSecondStatement = hours;
    let colon = ":";

    if (hours === 0) {
      hoursFirstStatement = "";
      hoursSecondStatement = "";
      colon = "";
    }

    // This `${}` allows adding javascript variables in strings
    const display = `${hoursFirstStatement}${hoursSecondStatement}${colon}${
      remainderMinutes < 10 ? "0" : ""}${remainderMinutes}:${
      remainderSeconds < 10 ? "0" : ""}${remainderSeconds}`;
    timerDisplay.textContent = display;
    document.title = display + " " + "(" + actionTypeSwitch + ")";
  }

  function displayEndTime(timestamp) {
    const end = new Date(timestamp);
    const hours = end.getHours();
    const minutes = end.getMinutes();
    endTime.textContent = `This session ends at ${hours < 10 ? "0" : ""}${hours}:${
      minutes < 10 ? "0" : ""}${minutes}`;
  }

  function changeBreakSettings() {
    const breakChangeValue = parseInt(this.dataset.settings);
    if ((breakValueSettings <= 1 && breakChangeValue === -1) ||
        (breakValueSettings >= 30 && breakChangeValue === 1))  {
      return; // Do nothing when this conditions are fulfilled
    } else {
      breakValueSettings = breakValueSettings + breakChangeValue;
      breakValue.textContent = breakValueSettings + ' min';
    }
  }

  function changeWorkSettings() {
    const workChangeValue = parseInt(this.dataset.settings);
    if ((workValueSettings <= 5 && workChangeValue === -1) ||
        (workValueSettings >= 120 && workChangeValue === 1))  {
      return; // Do nothing when this conditions are fulfilled
    } else {
      workValueSettings = workValueSettings + workChangeValue;
      workValue.textContent = workValueSettings + ' min';
    }
  }

  breakSettings.forEach(button => button.addEventListener("click", changeBreakSettings));
  workSettings.forEach(button => button.addEventListener("click", changeWorkSettings));
  buttonMain.addEventListener("click", startAndReset);
}());

1 个答案:

答案 0 :(得分:0)

您需要clearInterval()timeCalc&amp;在secondsLeft < 0的情况下更新显示。因为当你不清除它时,当它显示&#34; 1秒左右&#34;时,timeCalc的调用将进入 if 语句并返回,并且永远不会更新显示和timeCalc永远不会清晰,你会进入无限循环。