HTML часы идут неравномерно
У меня на странице есть следующие часы:
function change_time(field){
field.textContent = new Date().toLocaleTimeString()
}
let date_time_field = document.querySelector('.preview_date_time')
setInterval(change_time, 500, date_time_field)
<div class="preview_date_time"></div>
Они обновляются каждые 500 миллисекунд. Когда время в системных часах кратно 500 миллисекундам, секунды на странице могут сменяться неравномерно. Например, секунда может смениться чаще, чем раз в 1000 миллисекунд. Понаблюдайте за таймером секунд 20 и вы поймёте о чём я говорю.
Подскажите пожалуйста, как я могу избавиться от дёрганья времени на странице?
Ответы (2 шт):
Вообще, такое происходит из-за того что на самом деле интервал не ровный, часто бывает что интервал опаздывает на пару (или больше) миллисекунд. Можно в этом убедиться:
function checkTime() {
const now = Date.now()
return new Promise(res => {
setTimeout(() => {
const timePassed = Date.now() - now
res(timePassed)
}, 500)
})
}
checkTime().then(time => {
console.log('Прошло ' + time + ' миллисекунд')
})
Можно сделать вот так:
function change_time(field) {
field.textContent = new Date().toLocaleTimeString()
}
let date_time_field = document.querySelector('.preview_date_time')
requestAnimationFrame(function onUpdate() {
change_time(date_time_field)
requestAnimationFrame(onUpdate)
})
<div class="preview_date_time"></div>
Но насчёт производительности ничего не обещаю. Всё таки обновлять элемент, с такой частатой, как и обновляется монитор, дело такое.
Можно решить задачу с минимальной тратой процессора, если отказаться от setInterval в пользу setTimeout.
Миллисекунды из текущей даты вычитаем из тысячи - это время до начала следующей секунды. Добавляем к нему десять миллисекунд. Это время в начале следующей секунды, где нас и вызовет setTimeout. Это способ гарантирует от попадания на границу секунды. Получается настолько равномерный таймер, насколько это может обеспечить setTimeout. На незагруженной странице ошибки будут в районе одной миллисекунды. Код выполняется раз в секунду, так редко как это минимально необходимо:
const field = document.querySelector('.preview_date_time');
const next_tick = () => {
const date = new Date();
field.textContent = date.toLocaleTimeString();
setTimeout(next_tick, 10 + 1000 - date.getMilliseconds());
};
next_tick();
<div class="preview_date_time"></div>
P.S. По стандарту можно было бы не прибавлять десять миллисекунд к началу следующей секунды. Задержка должна быть не меньше заданной - раньше начала секунды вызова быть не может. Но я не уверен что браузеры строго следуют стандарту, поэтому лучше прибавить.