JavaScript setTimeout и изменения системного времени вызывают проблемы
Я заметил, что если бы я установил setTimeout
в течение 1 минуты в будущем, а затем изменил свое системное время на 5 минут в прошлом, функция setTimeout
запустится через 6 минут.
Я сделал это потому, что хотел видеть, что происходит во время перехода на летнее время на системные часы.
На моей веб-странице в JavaScript используется функция setTimeout
для автоматического обновления страницы каждые 5 секунд, и, если произойдет переход на летнее время, информация о странице замерзнет в течение часа. Есть ли способ обхода?
Изменить: обновляю страницу с помощью Ajax, я не хочу обновлять всю страницу.
Ответы
Ответ 1
Что я сделаю, так это изменение от открытия нового запроса Ajax каждые 5 секунд, чтобы использовать Comet (длительный опрос). Это лучший вариант, потому что сервер будет каждый раз вносить новые результаты в браузер каждый раз, когда они понадобятся, это может быть каждые 5 секунд на стороне сервера или каждый раз, когда доступна новая информация.
Еще лучше было бы использовать сетевые сокеты и вернуть Comet. Это легко реализовать с помощью Faye или socket.oi.
Существуют и другие варианты, такие как CometD o Ape.
Ответ 2
Используйте setInterval
вместо setTimeout
, и ваши проблемы должны быть решены:)
Update:
Если вы действительно не можете использовать setTimeout или setInterval, вы можете попробовать иметь скрытую iframe
, которая загружает простую HTML-страницу, которая выглядит примерно так:
<html>
<head>
<meta http-equiv="refresh" content="300"/>
<script>
document.domain='same as parent page';
top.ajax_function_you_wish_to_trigger();
</script>
</head>
<body>
</body>
</html>
Если вам повезет, обновление meta не вызовет у вас те же проблемы.
Другим решением было бы переместить запуск события на сервер с помощью server push. Есть много причин не делать этого, не в последнюю очередь, чтобы вы централизовали события и делали их обузой на сервере, но это можно было бы считать последним средством.
Ответ 3
Вы можете использовать обновление метатега для этого. Этот код обновит страницу каждые 5 секунд:
<meta http-equiv="refresh" content="5">
Что касается javascript-вопроса, возможно, именно так, как браузер обрабатывает setTimeout. Он сообщает браузеру, что он выполняет код в установленное время, а затем, когда часы меняются, код все еще выполняется в то время до изменения тактового сигнала? Просто догадаться, но мне придется помнить об этом в следующий раз, когда я использую setTimeout.
Изменить: Хорошо, это не сработает для ajax
Изменить снова: это действительно хороший вопрос. Я уверен, что setTimeout функционирует, как я сказал выше, но ничего себе, это мозговой тизер.
Ответ 4
Вы можете вытащить и выполнить проверку if (Date in range foo)
. В основном проверьте, находится ли текущая отметка времени в течение 5 секунд от летнего времени, а затем просто обновите страницу, а затем, используя setTimeout
.
Таким образом, пользователи получают незначительное раздражение вблизи известного изменения времени, но страница не будет зависеть в течение часа.
Ответ 5
Недавно я столкнулся с этой проблемой. В моем случае изменение времени может привести к серьезным финансовым потерям, поэтому мне пришлось серьезно относиться к этому.
Некоторая предыстория:
- IE и Opera обрабатывают правильное изменение времени системы (никаких побочных эффектов для setTimeout, setInterval).
- FF < 4.0, и браузер, основанный на Webkit, не справляется с изменением времени до прошлого (точно так же, как описано). Примечание: таймеры в Chrome, однако, останавливаются только через некоторое время ~ 2-60 с.
Мое решение: используйте какое-либо событие из пользовательского взаимодействия (т.е. mousemove, mouseove и т.д.), чтобы вызвать проверку изменения времени.
Clock.prototype.checkLocalTime = function(){
var diff = Date.now()- this.lastTimestamp;
if ( diff < 0 || diff > 20000) { // if time shifted back or more than 20s to the future
console.warn('System time changed! By ' + diff + 'ms' );
this.restartTimer();
this.getServerTime();
}
this.lastTimestamp = time;
}
Как вы можете заметить, я перезапускаю таймер и дополнительно синхронизую время с сервером.