我注意到如果我将来将setTimeout
设置为1分钟,然后将系统时间更改为过去5分钟,则setTimeout
功能将在6分钟内触发。
我这样做是因为我想看看在夏令时改变系统时钟时会发生什么。
我的JavaScript网页使用setTimeout
功能每5秒自动刷新一次页面,如果夏令时发生,那么页面信息会冻结一小时。有解决方法吗?
编辑:我正在使用Ajax更新页面,我不想刷新整个页面。
答案 0 :(得分:4)
使用setInterval
代替setTimeout
,您的问题应该得到解决:)
更新
如果你真的不能使用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>
如果你很幸运,元刷新不会给你带来同样的问题。
另一种解决方案是通过server push将事件触发移动到服务器。有很多理由不这样做,尤其是你集中了事件并使它们成为服务器的负担,但它可以被认为是最后的手段。
答案 1 :(得分:4)
我要做的是从每5秒打开一个新的Ajax请求改为使用Comet(长轮询)。这是一个更好的选择,因为服务器会在每次需要时将新结果推送到浏览器,这可能是服务器端的每5秒或每次有新信息时。
更好的方法是使用网络套接字并让Comet作为后退。这可以通过Faye或socket.oi轻松实现。
还有其他选择,例如CometD o Ape。
答案 2 :(得分:1)
我最近也遇到过这个问题。在我看来,时间的变化可能导致严重的财务损失,所以我不得不认真对待。
一些背景知识:
我的解决方案:使用来自用户交互的一些事件(即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;
}
您可以注意到我重启计时器并另外与服务器同步时间。
答案 3 :(得分:0)
您可以使用元标记刷新来执行此操作。此代码每5秒刷新一次页面:
<meta http-equiv="refresh" content="5">
至于javascript问题,它可能只是浏览器处理setTimeout的方式。它告诉浏览器在设定的时间执行代码,然后当时钟发生变化时,代码仍然在时钟变化之前执行?只是一个猜测,但下次我使用setTimeout时我必须牢记这一点。
编辑:好的,这对ajax不起作用 再次编辑:这是一个非常好的问题。我确信setTimeout的功能如上所述,但哇,这是一个脑筋急转弯。
答案 4 :(得分:0)
你可以捏造并进行if (Date in range foo)
检查。基本上检查当前时间戳是否在夏令时的5秒内,然后立即刷新页面,而不是使用setTimeout
。
这样,用户可以在已知的时间变化附近获得轻微的烦恼,但页面不会冻结一小时。
答案 5 :(得分:0)
我发现使用window.performance给了我更准确的结果,并在系统时间变化时保持一致。
我用这个方法来获取setInterval内的当前时间,这样倒数计时器就不会受到系统时间变化的影响。我是根据给定时间内的滴答数计算出来的,试图通过改变系统时钟来防止计时器上的作弊(获得更多时间)
getCurrentTime = () => {
return window.performance ?
performance.timing.navigationStart + performance.now() : Date.now();
}
tick() {
let now = this.getCurrentTime();
if (this.calibrateTime) { //calibrate with a given server time
now -= this.timeCalibration;
}
const elapsedSeconds = (now - this.startedAt) / 1000;
if (elapsedSeconds > this.props.timeLimit + this.props.submitBuffer) {
clearInterval(this.interval);
this.props.onTimeUp();
}
let secondsRemaining = this.props.timeLimit - Math.floor(elapsedSeconds);
if (secondsRemaining < 0) secondsRemaining = 0;
}
startTimer() {
if (!this.startedAt) {
this.startedAt = Date.now();
}
this.setState({ started: true }, () => {
this.interval = setInterval(this.tick.bind(this), 500);
});
}