5

私は非常に時間に敏感な Web アプリケーションに取り組んでいます。私に与えられたビジネス ルールの 1 つは、クライアントの時計の時刻に関係なく、アプリケーションの動作は常に Web サーバーの時刻に依存する必要があるというものです。これをユーザーにわかりやすくするために、Web アプリケーションでサーバーの時刻を表示するように依頼されました。

この目的のために、次の Javascript コードを作成しました。

clock = (function () {
var hours, minutes, seconds;

function setupClock(updateDisplayCallback) {
    getTimeAsync(getTimeCallback);

    function getTimeCallback(p_hours, p_minutes, p_seconds) {
        hours = p_hours;
        minutes = p_minutes;
        seconds = p_seconds;
        setInterval(incrementSecondsAndDisplay, 1000);
    }

    function incrementSecondsAndDisplay() {
        seconds++;
        if (seconds === 60) {
            seconds = 0;
            minutes++;
            if (minutes === 60) {
                minutes = 0;
                hours++;
                if (hours === 24) {
                    hours = 0;
                }
            }
        }
        updateDisplayCallback(hours, minutes, seconds);
    }
}

// a function that makes an AJAX call and invokes callback, passing hours, minutes, and seconds.
function getTimeAsync(callback) {
    $.ajax({
        type: "POST",
        url: "Default.aspx/GetLocalTime",
        contentType: "application/json; charset=utf-8",
        dataType: "json",
        success: function (response) {
            var date, serverHours, serverMinutes, serverSeconds;
            date = GetDateFromResponse(response);
            serverHours = date.getHours();
            serverMinutes = date.getMinutes();
            serverSeconds = date.getSeconds();
            callback(serverHours, serverMinutes, serverSeconds);
        }     
    })
}

return {
    setup: setupClock
};
})();

for に渡される関数updateDisplayCallbackは、Web ページに日付を表​​示する単純な関数です。

基本的な考え方は、Javascript が非同期呼び出しを行ってサーバーの時間を検索し、それをクライアントに保存してから、1 秒に 1 回更新するというものです。

最初はこれが機能しているように見えますが、時間が経つにつれて、表示される時間が毎分数秒遅れます。私はそれを一晩中動かしたままにし、翌朝に戻ったとき、それは1時間以上ずれていました! Web アプリケーションは一度に何日も開いたままになる可能性があるため、これはまったく受け入れられません。

Web ブラウザがサーバーの時刻を継続的かつ正確に表示するように、このコードを変更するにはどうすればよいですか?

4

3 に答える 3

6

Javascript の setInterval は、このような時間を維持できるほど正確ではありません。

私の解決策は次のとおりです。

  1. サーバーの時間をミリ秒単位で定期的に取得します (2 つのクロックがそれほど大きくずれることはほとんどないため、それほど頻繁である必要はありません)。
  2. クライアント時間をミリ秒単位で取得します
  3. サーバーとクライアント (クライアント サーバー) 間のクロック偏差を計算します。
  4. クライアント時刻を取得し、時計の偏差を追加して、時計の表示を定期的に更新します。

編集:より正確にするために、サーバーのリクエストのラウンドトリップ時間を測定し、それを2で割って、その遅延をクロック偏差に掛けることができます。往復の期間が対称的であると仮定すると、より正確な計算が得られます。

于 2013-03-29T14:26:19.863 に答える
2

setInterval時間が重要なイベントをスケジュールするための信頼できる方法ではありません。1000msその時点での JavaScript のビジー状態に応じて、コールバックの実行にかかる時間が短くなったり長くなったりする場合があります。

より良いアプローチは、より短い間隔をとり、 を使用new Date().getTime()して 1 秒が経過したかどうかを確認することです。

ブラウザが許可する最小間隔は high10です。

于 2013-03-29T14:21:55.393 に答える
0

答えてくれてありがとう。有用な情報が含まれている限り、両方の回答に賛成票を投じました。ただし、どちらの回答でも規定されている正確な回答は使用していません。

私が最終的に決めたのは少し違います。

学んだことを個人のウェブページに書きました。

まず第一に、setInterval(..., 1000)1 秒に 1 回何かを長時間実行するには、使用するだけでは不十分であることがわかりました。ただし、変更する秒を探すためにはるかに短い間隔で時間を「ポーリング」することは、私には非常に非効率的です。

サーバー時間とクライアント時間の間の「オフセット」を追跡することは理にかなっていると判断しました。

私の最終的な解決策は、次のことです。

(1) サーバーに対して AJAX 呼び出しを実行して時間を取得します。この関数はクライアントの時刻もチェックし、サーバー時刻とクライアント時刻の差をミリ秒単位で計算します。ネットワークの遅延やその他の要因により、この最初のフェッチは数秒ずれることがあります。私の目的では、これで問題ありません。

(2)tick関数を実行します。実行するたびtickに、最後にtick実行されてからの経過時間がチェックされます。この時間を使用して、渡される引数を計算setTimeoutし、時間表示が約 1 秒に 1 回更新されるようにします。

(3)tick関数が表示される時間を計算するたびに、クライアント時間がかかり、ステップ (1) で計算された差が追加されます。このように、クライアントが時間を正しく設定することに依存することはありませんが、経過時間を正確に測定することはクライアントに依存します。私の目的では、これで問題ありません。setTimeout最も重要なことは、他のプロセス (モーダル ダイアログなど) によってどのように不正確または中断される可能性があるかに関係なく、表示される時間は常に正確である必要があるということです。

于 2013-03-29T16:40:22.093 に答える