JavaScript SetimeOutとシステム時間の変更は問題を引き起こします
-
28-10-2019 - |
質問
設定した場合に気づきました setTimeout
将来1分間、システム時間を過去に5分に変更してください。 setTimeout
関数は6分でトリガーされます。
これをやったのは、システムクロックに夏時間の変化中に何が起こるかを見たかったからです。
私のJavaScriptのWebページはaを使用します setTimeout
5秒ごとにページを自動的に更新するように機能し、夏時間の節約が発生した場合、ページ情報は1時間凍結します。回避策はありますか?
編集:Ajaxを使用してページを更新しています。ページ全体を更新したくありません。
他のヒント
使用する 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>
運が良ければ、メタの更新は同じ問題を引き起こすことはありません。
別の解決策は、イベントを介してサーバーに発砲することです サーバープッシュ. 。これを行わない理由はたくさんありますが、少なくともイベントを集中化してサーバーに負担をかけることはありませんが、最後の手段と見なされる可能性があります。
私は最近、この問題にも遭遇しました。私の場合、時間の変化は深刻な財政的な損失を引き起こす可能性があるため、私はそれを真剣に受け止めなければなりませんでした。
いくつかの背景:
- IEとOperaはシステムの時間の変更を適切に処理します(SetimeOutへの副作用はありません、SetInterval)。
- FF <4.0およびすべてのWebKitベースのブラウザは、過去への変化時間を処理できません(記述したとおり)。注:クロムのタイマーは、しばらく2〜60秒後にのみ停止します。
私の解決策:ユーザーインタラクション(Mousemove、マウスブなど)からのイベントを使用して、時間の変更チェックをトリガーします。
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;
}
ご存知のように、タイマーを再起動し、サーバーと時間をさらに同期します。
これを行うには、メタタグの更新を使用できます。このコードは5秒ごとにページを更新します:
<meta http-equiv="refresh" content="5">
JavaScriptの質問に関しては、ブラウザがSettimeOutを処理する方法だけかもしれません。これにより、ブラウザは設定された時間にコードを実行するように指示し、その後、クロックが変更された場合、クロックが変更される前にコードがまだ実行されますか?ただ推測しますが、次回SettimeOutを使用するときはそのことを念頭に置かなければなりません。
編集:OK、Ajaxの編集では機能しません。これは本当に良い質問です。私が上で言ったように、SetimeOutが機能すると確信していますが、すごい、これは脳ティーザーです。
あなたはファッジして行うことができます if (Date in range foo)
小切手。基本的に、現在のタイムスタンプが夏時間から5秒以内にあるかどうかを確認し、使用するのではなくすぐにページを更新するだけです setTimeout
.
このようにして、ユーザーは既知の時間の変更の近くでマイナーな迷惑を取得しますが、ページは1時間凍結しません。
使用していることがわかりました window.performance 私により正確な結果を与え、システムの時間が変わったときに物事を一貫性に保ちました。
これを使用して、現在の時間をSetInterval Tickの内側に入れて、カウントダウンタイマーがシステム時間の変更の影響を受けないようにしました。システムクロックを変更することにより、タイマーの不正行為を防止しようとするために、特定の時間からのダニの数に基づいて計算していました
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);
});
}