Это обычное явление с синхронизацией почти во всех языках и библиотеках.Вещи никогда не попадут точно в ровное время.
Когда вы используете setTimeout()
, вы на самом деле говорите: «По прошествии x миллисекунд, запустите эту функцию».Уловка в том, что она делает другие вещи, поэтому на самом деле происходит после прохода x миллисекунд, эта функция ставится в очередь для вызова, но для ее запуска может потребоваться еще несколько миллисекунд.
Короче говоря,вы не можете создать настоящие часы исключительно в JavaScript, потому что они всегда будут дрейфовать;обычно только на несколько миллисекунд каждый тик, но все хуже и хуже.
let last = Date.now();
let shouldBe = -1000; // account for first tick
let actual = 0;
const run = () => {
const now = Date.now();
shouldBe += 1000;
actual += now - last;
console.log({ sinceLast: now - last, actual, shouldBe, drift: actual - shouldBe });
last = now;
setTimeout(run, 1000);
};
run();
Однако вы можете использовать setTimeout()
с некоторым интервалом (обычно <1 секунда), после чего вы используете объект <code>Date (который может читать данные клиента).системное время), чтобы узнать текущее время и обновить его таким образом.
const clock = document.querySelector('div');
const updateClock = () => {
const now = new Date();
clock.innerHTML = `${now.getHours()}:${now.getMinutes()}:${now.getSeconds()}`;
setTimeout(updateClock, 500);
};
updateClock(); // start it
<div>XX:XX:XX</div>
Он будет отключен на несколько миллисекунд каждый тик, но он вернется на прежний уровень и не будет иметь большого значения.Это единственный реальный подход, позволяющий делать это с любым уровнем точности.