Я протестировал простой код таймера для отображения таймера на веб-сайте. Таймер работает нормально, когда я нахожусь на странице. Но когда я перехожу на другую страницу или сайт, через некоторое время, когда я возвращаюсь на страницу таймера, я вижу, что таймер не работал правильно в интервале.
Предположим, я ухожу со страницы на 5 минут. Так что когда вернусь, надо посмотреть 00:05:00. Но отображается 00:01:00 (вокруг).
Но если я не покидаю страницу, все работает нормально.
Каково решение?
timerElement = document.getElementById("time");
let seconds = 0, minutes = 0, hours = 0;
timerInterval = setInterval(function() {
seconds++;
if (seconds === 60) {
seconds = 0;
minutes++;
if (minutes === 60) {
minutes = 0;
hours++;
}
}
const formattedTime = `${String(hours).padStart(2, "0")}:${String(minutes).padStart(2, "0")}:${String(seconds).padStart(2, "0")}`;
timerElement.textContent = formattedTime;
}, 1000);<h1 id = "time"></h1>Даже я разместил это на странице github. Но результат тот же.
Во-первых, не используйте такие вещи, как hours++ внутри интервала, используйте объект Date и сравните его с некоторой датой начала.
Аргумент задержки в setInterval() нельзя использовать для хронографической задачи.
если вы хотите, чтобы он был действительно надежным, не увеличивайте секунды, а вместо этого рассчитайте окончательную метку даты и сохраните ее в localStorage. Затем при отображении счетчика всегда сравнивайте текущую метку даты с меткой в localStorage, чтобы вычислить оставшиеся секунды.



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


этот будет выполнять работу по реальному прошедшему времени при повторной активации окна, без ошибок, когда он находится в режиме ожидания системы
const
timerElement = document.querySelector('#timer-element')
, Digits2 = t => t<10 ? `0${t}` : t
, one_Sec = 1000
, one_Min = one_Sec * 60
, one_Hour = one_Min * 60
, ZeroTime = new Date().getTime()
;
setInterval(()=>
{
let tim = new Date().getTime() - ZeroTime
, h = Math.floor( tim / one_Hour)
, m = Math.floor((tim % one_Hour) / one_Min )
, s = Math.floor((tim % one_Min ) / one_Sec )
;
timerElement.textContent = `${Digits2(h)}:${Digits2(m)}:${Digits2(s)}`
},500);<h1 id = "timer-element"></h1>Если вы ищете более подробную информацию: см. там
setInterval и setTimeout вызывают обратный звонок не в точное время. Когда страница находится на скрытой вкладке, браузер может отложить/регулировать обратные вызовы.
Я бы предложил попробовать requestAnimationFrame (который не вызывается на скрытой вкладке, и это хорошо) и сравнить текущее время со временем начала таймера. Использование requestAnimationFrame позволит более точно обновлять таймер на экране.
Форматирование можно выполнить с помощью Intl.DateTimeFormat (используется здесь для упрощения примера, требуются некоторые настройки для обработки часов > 24):
const start = new Date, today = new Date;
today.setHours(0, 0, 0, 0);
let running = true;
const format = new Intl.DateTimeFormat('en', {
hourCycle: 'h23',
hour: '2-digit',
minute: '2-digit',
second: '2-digit',
fractionalSecondDigits: 2
});
// add today's timestamp so the timezone would be properly handled
const timer = () => requestAnimationFrame(() => {
$time.textContent = format.format(new Date - start + +today);
running && timer();
});
timer();
console.info('started');button{
padding: 10px;
min-width: 100px;
border-radius: 5px;
cursor:pointer;
background:lightblue;
}<h1 id = "$time" style = "font-family:monospace"></h1>
<button onmousedown = "running = false">Stop</button>
Некоторые браузеры, например Microsoft Edge, автоматически переводят ваши вкладки в спящий режим после некоторого времени бездействия.