Таймер на JavaScript


Это мой первый приложение на JavaScript (он вдохновлен этот таймер). Как я могу улучшить его?

Мне пришлось установить setInterval() в 980ms вместо 1000 мс, потому что он был медленнее, чем реальные часы по какой-то причине.

Полное приложение

Главная ДШ:

var btn1 = document.getElementById('start');
var btn2 = document.getElementById('pause');
var btn3 = document.getElementById('restart')

var h1 = document.getElementById('h1');
var h1Clr = h1.style.color;
var h1Nmb = 0;

var h2 = document.getElementById('h2');
var h2Clr = h1.style.color;
var h2Nmb = 0;

var m1 = document.getElementById('m1');
var m1Clr = h1.style.color;
var m1Nmb = 0;

var m2 = document.getElementById('m2');
var m2Clr = h1.style.color;
var m2Nmb = 0;

var s1 = document.getElementById('s1');
var s1Clr = h1.style.color;
var s1Nmb = 0;

var s2 = document.getElementById('s2');
var s2Clr = h1.style.color;
var s2Nmb = 0;

window.addEventListener("keydown", function (e) {
    var keycode = String.fromCharCode(e.keyCode);
    var isNmbr = Number(keycode);
    if (s2Clr == 'white' && (isNmbr || keycode == 0)) {
        s2.textContent = String.fromCharCode(e.keyCode);
        s2.style.color = 'rgb(192, 33, 33)';
        s2Clr = 'rgb(192, 33, 33)';
        window.s2Nmb = Number(s2.textContent);
    } else if (s1Clr == 'white' && (isNmbr || keycode == 0)) {
        s1.textContent = String.fromCharCode(e.keyCode);
        s1.style.color = 'rgb(192, 33, 33)';
        s1Clr = 'rgb(192, 33, 33)';
        window.s1Nmb = Number(s1.textContent);
    } else if (m2Clr == 'white' && (isNmbr || keycode == 0)) {
        m2.textContent = String.fromCharCode(e.keyCode);
        m2.style.color = 'rgb(192, 33, 33)';
        m2Clr = 'rgb(192, 33, 33)';
        window.m2Nmb = Number(m2.textContent);
    } else if (m1Clr == 'white' && (isNmbr || keycode == 0)) {
        m1.textContent = String.fromCharCode(e.keyCode);
        m1.style.color = 'rgb(192, 33, 33)';
        m1Clr = 'rgb(192, 33, 33)';
        window.m1Nmb = Number(m1.textContent);
    } else if (h2Clr == 'white' && (isNmbr || keycode == 0)) {
        h2.textContent = String.fromCharCode(e.keyCode);
        h2.style.color = 'rgb(192, 33, 33)';
        h2Clr = 'rgb(192, 33, 33)';
        window.h2Nmb = Number(h2.textContent);
    } else if (h1Clr == 'white' && (isNmbr || keycode == 0)) {
        h1.textContent = String.fromCharCode(e.keyCode);
        h1.style.color = 'rgb(192, 33, 33)';
        h1Clr = 'rgb(192, 33, 33)';
        window.h1Nmb = Number(h1.textContent);
    }
});
var myVar;
btn1.onclick = function () {
    window.myVar = setInterval(myTimer, 980);
}
btn2.onclick = function () {
    clearInterval(window.myVar);
}
btn3.onclick = function () {
    window.location.reload();
}
function myTimer() {
    //s2
    if (s2Nmb != 0) {
        if (s2Nmb == 0) {
            s2Nmb = 10;
        };
        s2Nmb--;
        s2.textContent = s2Nmb;
    } else {
        s2Nmb = 9;
        s2.textContent = s2Nmb;
        if (s2Nmb == 0) {
            s2Nmb = 10;
        };
    }
    //s1
    if (s2Nmb == 9) {
        if (s1Nmb == 0) {
            s1Nmb = 6;
        };
        s1Nmb--;
        s1.textContent = s1Nmb;

    }

    //section Minutes
    //m2
    if (s1Nmb == 5 && s2Nmb == 9) {
        if (m2Nmb == 0) {
            m2Nmb = 10;
        };
        m2Nmb--;
        m2.textContent = m2Nmb;

    }
    //m1
    if (m2Nmb == 9 && s1Nmb == 5 && s2Nmb == 9) {
        if (m1Nmb == 0) {
            m1Nmb = 6;
        };
        m1Nmb--;
        m1.textContent = m1Nmb;

    }
    //h2
    if (m1Nmb == 5 && m2Nmb == 9 && s1Nmb == 5 && s2Nmb == 9) {
        if (h2Nmb == 0) {
            h2Nmb = 10;
        };
        h2Nmb--;
        h2.textContent = h2Nmb;

    }
    //h1
    if (h2Nmb == 9 && m1Nmb == 5 && m2Nmb == 9 && s1Nmb == 5 && s2Nmb == 9) {
        if (h1Nmb == 0) {
            h1Nmb = 6;
        };
        h1Nmb--;
        h1.textContent = h1Nmb;

    }
    //alert
    if (h1Nmb == 0 && h2Nmb == 0 && m1Nmb == 0 && m2Nmb == 0 && s1Nmb == 0 && s2Nmb == 0) {
        clearInterval(window.myVar);
        var snd = new Audio("alarm_beep.wav"); 
        snd.volume = 0.3;
        snd.play();
    }

};


503
1
задан 8 февраля 2018 в 07:02 Источник Поделиться
Комментарии
1 ответ

Точность таймера

В JS таймеры единственной гарантией того, что по крайней мере delay миллисекунд, прежде чем ваша функция вызывается. Это не гарантирует точное время. Что происходит под капотом, когда вы называете setInterval или setTimeout заключается в том, что ваш обратный вызов становится в очередь на выполнение. Яш выбирает только обратного вызова, когда он был снят стеке выполнения. Если что-то держит движок JavaScript, что обратный вызов может быть вызван позже, чем ожидалось.

Реализация таймера

Реализация таймеров также различаются. Если я правильно помню, самый быстрый интервал не менее 4 мс для обычных таймеров. Так что задержка 0мс 0мс не реально. Браузер продавцы могут замедлить или полностью остановить таймеры таймеры, когда окно не в фокусе, или когда он обнаруживает бездействия для экономии заряда батареи.

Гарантируя точность таймера

Один трюк, чтобы гарантировать точность времени, чтобы никогда не полагаться на таймер. Вместо этого, вы смотрите в реальном времени. Чтобы сделать это, вы создать таймер, который работает быстрее, чем второй. На каждый вызов, Вызов Date.now() и сравнить метки времени.



// Implementing a timer using just the timer
var intervalInput = document.getElementById('interval')
var intervalSeconds = 0
setInterval(() => {
intervalInput.value = ++intervalSeconds
}, 1000)

// Implementing a by computing seconds from real time since the start.
var realInput = document.getElementById('real')
var start = Date.now()
setInterval(() => {
// Compute how many seconds since we started
realInput.value = Math.floor((Date.now() - start) / 1000)
}, 200)


<label>Interval seconds:</label> <input id="interval">
<label>Real seconds:</label> <input id="real">


Представление времени

Наивная реализация таймера предполагает хранение единиц времени (секунд, минут, часов и т. д.) В отдельные переменные, и писать каскадной логики (т. е. от 59с до 0С, с шагом мин.), Чтобы обновить значения. Это не очень масштабируемый, как только вы начинаете добавлять больше единицы. Это также трудно отлаживать, поскольку вы должны пройти через это логика.

Лучший способ сделать это, чтобы сохранить время в одном значении, как МС, и вычислить блоков от него. Блоки являются лишь функции значение миллисекунды. Таймер обратного отсчета-это просто будущее timestamp как начальное значение минусом текущую метку времени.



const hoursInput = document.getElementById('hours')
const minutesInput = document.getElementById('minutes')
const secondsInput = document.getElementById('seconds')
const startButton = document.getElementById('start')
const pauseButton = document.getElementById('pause')
const resetButton = document.getElementById('reset')

const pad = v => `00${v}`.slice(-2)

// Functions that compute units from a millisecond value
const hours = m => Math.floor((m / 3600000) % 24)
const minutes = m => Math.floor((m / 60000) % 60)
const seconds = m => Math.floor((m / 1000) % 60)

// Render function
const render = v => {
hoursInput.value = pad(hours(v))
minutesInput.value = pad(minutes(v))
secondsInput.value = pad(seconds(v))
}

// This is the value you ask from the user
const duration = 3610000

let remaining = duration
let timer = null
let end = 0

startButton.addEventListener('click', e => {
if (timer) return

// Get end timestamp based on current time + remaining time
end = Date.now() + remaining

// Render the remaining time every 16ms (approx 60fps)
timer = setInterval(() => {
render(end - Date.now())
}, 16)
})

pauseButton.addEventListener('click', e => {
// Do nothing if timer not running
if(!timer) return

// Otherwise, clear timer
clearInterval(timer)
timer = null

// Note the remaining time
remaining = end - Date.now()
render(remaining)
})

resetButton.addEventListener('click', e => {
// Do nothing if timer not running
if(!timer) return

// Otherwise, clear timer
clearInterval(timer)
timer = null

// Reset remaining to original duration
remaining = duration
render(remaining)
})

render(remaining)


<input id="hours">h <input id="minutes">m <input id="seconds">s

<button type="button" id="start">Start</button>
<button type="button" id="pause">Pause</button>
<button type="button" id="reset">Reset</button>



Наконец, один маленький недостаток в вашем таймер обратного отсчета, что ваша кнопка "Пуск" не проверить, если таймер уже запущен. Это приводит к запуску другой таймер на JS, удвоение декремента.

2
ответ дан 9 февраля 2018 в 03:02 Источник Поделиться