我需要在浏览器控制台中进行一些精确的计时。它向另一个使用 pool.ntp.org 的网站发送请求来同步自己的时间。如果是+-50ms就好了。我知道我的 ping 值有所不同,但没关系。我通常有一个相当稳定的 ping 值,大约 25。 我的第一个测试是使用超时功能,但这非常不准确。特别是如果您必须设置更长的超时时间几个小时。 然后我添加了对 https://worldtimeapi.org/api/ip 的调用,以获得更准确的开始时间。我还在实际调用之前 10 秒添加了对该 api 的第二次调用,以重置计时器并更加精确。 现在我的奇怪行为。 我想在 2 小时 10 分钟内执行一个函数。所以我将第一个 timeOut 设置为 2 小时 9 分 50 秒。然后我再次从 Web api 调用当前时间,并从“executeTime-newFetchedTime”设置新的超时。
我记录了所有的差异时间。这有点切中要害。 在实际调用前 10 秒,我得到了新的当前时间。我设置了新的超时并记录新的超时持续时间。
我的问题是,我在执行前10秒查询新时间。我找回时间,设置新的时间。这始终约为 8000-9500 毫秒(因此第一次超时约为 1-2 秒已经关闭)。新的超时完成后,它会执行该函数。但它仍然关闭。它不是由随机的东西造成的,它的关闭有点完全是由第一次超时测量到的差异造成的。
因此,如果我测量第一次和第二次调用之间的时间差为 1450 毫秒,则我的执行时间大约会减少 1400-1500 毫秒。 如果测量的时间差在 800ms 左右,则执行时间为 750-850ms。 所以不知何故,我的代码中有一个错误(虽然我找不到它,这是一个非常简单的代码),或者我的 chrome 浏览器有一些非常奇怪的行为。
这是代码:
const network_delay = 50
//execute the function at 2023.09.18 15:30:35:500
const executeTime = new Date('2023.09.18 15:30:35').getTime() + 500 - network_delay
const fetchTime = executeTime - 10000;
function fetchCurrentTime(callback) {
fetch('https://worldtimeapi.org/api/ip')
.then(response => response.json())
.then(data => {
const serverTime = new Date(data.utc_datetime).getTime();
callback(serverTime);
})
.catch(error => {
console.error('Error time API:', error);
});
}
fetchCurrentTime(serverTime1 => {
console.log("current time: " + serverTime1)
console.log("fetch time: " + new Date(fetchTime))
setTimeout(() => {
fetchCurrentTime(serverTime2 => {
console.log("time fetched again. now:" + serverTime2)
console.log("execute function in: " + (executeTime - serverTime2))
setTimeout(() => {
executeFunction();
}, (executeTime - serverTime2));
});
}, fetchTime - serverTime1);
})
我也尝试了动画框架,但这在后台不起作用。 我用网络工作者尝试过它,但由于它位于浏览器控制台中,我必须将代码编写为blod-url才能调用它,但在该代码中我无法访问该文档。但在我的执行函数中,我需要访问该文档。
如果第二次超时正确的话,我对当前的实现会很满意。有人知道如何“解决”这个问题吗?
您也许可以做这样的事情 - 定期测量您的时间偏差(如果您信任该时间提供商)并考虑您的延迟以及浏览器获取该时间所需的时间。
但正如所说,
setTimeout
不能保证非常准确。
let executeTime = Date.parse('2023-09-18T13:21:35Z');
async function fetchCurrentTime() {
const startTime = performance.now();
const response = await fetch('https://worldtimeapi.org/api/ip');
const data = await response.json();
const realTime = new Date(data.utc_datetime).getTime();
const endTime = performance.now();
const fetchTime = endTime - startTime;
return Math.round(realTime + fetchTime / 2); // Assume symmetric latency
}
async function tick() {
const realTime = await fetchCurrentTime();
const now = Date.now();
const skew = realTime - now;
if (now >= executeTime) {
console.log("Ding!", realTime - executeTime, "ms late");
executeTime = now + 15000;
}
const delay = Math.min(10000, executeTime - now - skew);
console.log(`${executeTime - now} ms to deadline, skew ${skew} ms, waiting for ${delay} ms`);
setTimeout(tick, delay);
}
tick();