Запускать таймеры обратного отсчета один за другим в Javascript - PullRequest
0 голосов
/ 03 мая 2018

Я пытаюсь создать сайт обратного отсчета, который запускает ряд расписаний в виде обратного отсчета один за другим. Каждое расписание представляет собой массив из пары строк, которые представляют время начала и время окончания каждого расписания.

Ожидаемое поведение:

Я хочу, чтобы второе расписание начиналось после окончания первого.

Текущее поведение:

После того, как первое расписание составлено, дата, показанная на веб-странице, показывает NaN для всех значений.

Пожалуйста, помогите мне понять, что я делаю неправильно, поскольку я новичок в программировании.

Codepen минимально завершенного проверяемого примера [Возможно, вам придется изменить время начала и время окончания графиков в будущем в зависимости от того, когда вы откроете его для воспроизведения выпуск]

Пример кода:

function getTimeRemaining(endtime) {
  var t = Date.parse(endtime) - Date.parse(new Date());
  var seconds = Math.floor((t / 1000) % 60);
  var minutes = Math.floor((t / 1000 / 60) % 60);
  var hours = Math.floor((t / (1000 * 60 * 60)) % 24);
  var days = Math.floor(t / (1000 * 60 * 60 * 24));
  return {
    'total': t,
    'days': days,
    'hours': hours,
    'minutes': minutes,
    'seconds': seconds
  };
}

function initializeClock(id, endtime) {
  var clock = document.getElementById(id);
  clock.style.display = 'block';
  var daysSpan = clock.querySelector('.days');
  var hoursSpan = clock.querySelector('.hours');
  var minutesSpan = clock.querySelector('.minutes');
  var secondsSpan = clock.querySelector('.seconds');

  function updateClock() {
    var t = getTimeRemaining(endtime);

    daysSpan.innerHTML = t.days;
    hoursSpan.innerHTML = ('0' + t.hours).slice(-2);
    minutesSpan.innerHTML = ('0' + t.minutes).slice(-2);
    secondsSpan.innerHTML = ('0' + t.seconds).slice(-2);

    if (t.total <= 0) {
      clearInterval(timeinterval);
    }
  }

  updateClock();
  var timeinterval = setInterval(updateClock, 1000);
}

// var deadline = new Date(Date.parse(new Date()) + 15 * 24 * 60 * 60 * 1000);
initializeClock('clockdiv', schedule);

var schedule = [
    ['2018-05-01', '2018-05-02 13:36:00'],
    ['2018-05-02 13:36:01', '2018-05-09']
];

// iterate over each element in the schedule
for(var i=0; i<schedule.length; i++){
  var startDate = schedule[i][0];
  var endDate = schedule[i][1];

  // put dates in milliseconds for easy comparisons
  var startMs = Date.parse(startDate);
  var endMs = Date.parse(endDate);
  var currentMs = Date.parse(new Date());

  // if current date is between start and end dates, display clock
  if(endMs > currentMs && currentMs >= startMs ){
      initializeClock('clockdiv', endDate);
  }
}

1 Ответ

0 голосов
/ 03 мая 2018

Я думаю, что проблема в основном в двух областях:

  1. Цикл for запускается только один раз, поэтому второе расписание никогда не запускается после его завершения (цикл for, очевидно, завершил бы выполнение и не запустился снова). В идеале этот цикл должен запускаться снова после окончания первого расписания.

  2. Функция очистки тайм-аута должна быть перемещена до обновления DOM, так как функция getTimeRemaining может возвращать несогласованные значения при завершении расписания.

Решения:

  1. Оберните код начала расписания в функцию startNewScheduleIfNeeded и запускайте эту новую функцию каждый раз, когда заканчивается расписание, и мы очищаем таймер

  2. Переместите проверку, чтобы увидеть, следует ли сбрасывать таймер над обновлением DOM в updateClock, чтобы избежать NaN значений

Пример кода:

function getTimeRemaining(endtime) {
    var t = Date.parse(endtime) - Date.parse(new Date());
    var seconds = Math.floor((t / 1000) % 60);
    var minutes = Math.floor((t / 1000 / 60) % 60);
    var hours = Math.floor((t / (1000 * 60 * 60)) % 24);
    var days = Math.floor(t / (1000 * 60 * 60 * 24));
    return {
        total: t,
        days: days,
        hours: hours,
        minutes: minutes,
        seconds: seconds
    };
}

function initializeClock(id, endtime) {
    var clock = document.getElementById(id);
    clock.style.display = "block";
    var daysSpan = clock.querySelector(".days");
    var hoursSpan = clock.querySelector(".hours");
    var minutesSpan = clock.querySelector(".minutes");
    var secondsSpan = clock.querySelector(".seconds");

    function updateClock() {
        var t = getTimeRemaining(endtime);
        // Solution Part 2: Move check before DOM update and return early if needed
        if (t.total <= 0) {
            clearInterval(timeinterval);
            // Schedule has ended, run function to start another if needed.
            startNewScheduleIfNeeded();
            return;
        }
        daysSpan.innerHTML = t.days;
        hoursSpan.innerHTML = ("0" + t.hours).slice(-2);
        minutesSpan.innerHTML = ("0" + t.minutes).slice(-2);
        secondsSpan.innerHTML = ("0" + t.seconds).slice(-2);
    }

    updateClock();
    var timeinterval = setInterval(updateClock, 1000);
}

// var deadline = new Date(Date.parse(new Date()) + 15 * 24 * 60 * 60 * 1000);
//initializeClock('clockdiv', schedule);

// Solution Part 1: Wrap schedule start in a function to resuse when schedules end
function startNewScheduleIfNeeded() {
    var schedule = [
        ["2018-05-03", "2018-05-03 11:17:00"],
        ["2018-05-03 11:17:00", "2018-05-09"]
    ];

    // iterate over each element in the schedule
    for (var i = 0; i < schedule.length; i++) {
        var startDate = schedule[i][0];
        var endDate = schedule[i][1];

        // put dates in milliseconds for easy comparisons
        var startMs = Date.parse(startDate);
        var endMs = Date.parse(endDate);
        var currentMs = Date.parse(new Date());

        // if current date is between start and end dates, display clock
        if (endMs > currentMs && currentMs >= startMs) {
            initializeClock("clockdiv", endDate);
        }
    }
}
startNewScheduleIfNeeded();

Другие наблюдения:

  1. был случайный вызов initializeClock, который я закомментировал
  2. Вам нужно использовать Date.parse, только если вы вводите строку (например, список расписаний). Вызов Date.parse(new Date()) является избыточным. Вы можете просто использовать new Date(). Кроме того, Date.parse НЕ возвращает целое число (миллисекунды). Он возвращает объект Date, который преобразуется в число при сравнении, например <
  3. Время окончания одного расписания должно быть равно времени начала следующего расписания, чтобы этот метод работал. Если у вас есть промежутки (даже одна секунда), функция запуска расписания будет выполняться перед проверкой, чтобы увидеть, находится ли текущее время между временем начала и временем окончания. (в примере в вашем вопросе время окончания первого расписания составляет '2018-05-02 13:36:00', а время начала следующего - '2018-05-02 13:36:01'. Это не сработает - время начала второго расписания должно быть '2018-05-02 13:36:00') .
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...