Синхронизировать интервал JavaScript с фактическим временем - PullRequest
0 голосов
/ 22 декабря 2018

Я хочу синхронизировать секунды с секундами реального времени (new Date()), чтобы они работали, если страница была загружена в середине секунды.

setInterval(() => {
    console.log("hey im not synchronized");
}, 1000);

Возможно ли это?

Ответы [ 2 ]

0 голосов
/ 22 декабря 2018

Для этой конкретной цели вам нужен самосинхронизирующийся цикл синхронизации.Основная идея состоит в том, чтобы не использовать setInterval(), а рассчитывать каждый раз, сколько миллисекунд спустя вы хотите, чтобы цикл запускался в следующий раз, и использовать setTimeout() для ожидания до тех пор.

Вот базовый пример:

function oncePerSecond(callback) {
    var timerFunc = function () {
        // get the current time rounded down to a whole second (with a 10% margin)
        var now = 1000 * Math.floor(Date.now() / 1000 + 0.1);
        // run the callback
        callback(now);
        // wait for the next whole second
        setTimeout(timerFunc, now + 1000 - Date.now());
    };
    timerFunc();
}

// create a demo timer
oncePerSecond(function (now) {
    document.getElementById('local').textContent = new Date(now).toString();
});

// add an artificial 0.5 second delay for the second timer
setTimeout(function () {
    oncePerSecond(function (now) {
        document.getElementById('utc').textContent = new Date(now).toUTCString();
    });
}, 500);
<p>The local time is now: <span id="local">...</span></p>
<p>The UTC time is now: <span id="utc">...</span></p>

Обратите внимание, что хотя два таймера в приведенном выше фрагменте запускаются с интервалом в полсекунды, они синхронизируются сразу после первого обновления.

Причина странного * fudge-фактора + 0.1 в Math.floor(Date.now() / 1000 + 0.1) заключается в том, что нет никакой гарантии, что таймер иногда не срабатывает рано, всего за несколько миллисекунд до того, как часы остановятся.Смещение в 0,1 секунды гарантирует, что мы будем округлять текущее время вперед в таких случаях, но мы все равно будем обычно округлять время вниз при первом обновлении (или после возможных неожиданных задержек).

Еще лучшеВ результате вы можете комбинировать эту технику с requestAnimationFrame(), чтобы ваши таймеры не запускались без необходимости, пока пользователь, например, просматривает другую вкладку:

function oncePerSecondAnim(callback) {
    var frameFunc = function () {
        // get the current time rounded down to a whole second (with a 10% margin)
        var now = 1000 * Math.floor(Date.now() / 1000 + 0.1);
        // run the callback
        callback(now);
        // wait for the next whole second
        setTimeout(timerFunc, now + 1000 - Date.now());
    }, timerFunc = function () {
        requestAnimationFrame(frameFunc);
    };
    timerFunc();
}

// create a demo timer
oncePerSecondAnim(function (now) {
    document.getElementById('local').textContent = new Date(now).toString();
});

// add an artificial 0.5 second delay for the second timer
setTimeout(function () {
    oncePerSecondAnim(function (now) {
        document.getElementById('utc').textContent = new Date(now).toUTCString();
    });
}, 500);
<p>The local time is now: <span id="local">...</span></p>
<p>The UTC time is now: <span id="utc">...</span></p>
0 голосов
/ 22 декабря 2018

Это возможно?

Да, вот так:

setTimeout(() => {
    setInterval(() => console.log("hey im synchronized"), 1000)
}, 1000 - new Date().getMilliseconds());
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...