制作一个需要 2560 毫秒才能在 JavaScript 中完成一圈的时钟

Making a clock that takes 2560ms to complete a revolution in JavaScript

我正在尝试为 Libet 任务制作一个时钟 - 心理学家使用的一项认知任务。按照惯例,这些时钟需要 2560 毫秒才能完成一圈。我的似乎 运行 慢了很多,我知道为什么了。

我在这里举了一个问题的例子:https://jsfiddle.net/Sumoza/re4v7Lcj/8/

在延迟 1 毫秒的 setInterval 的每次迭代中,我将手的旋转角度增加 (Math.PI*2)/2560,即以弧度表示的圆的 1/2560。因此,每毫秒增加其中之一应该在该毫秒数内完成圆圈。正如您从时钟中看到的那样,它运行得有点慢。任何人都可以阐明原因。有趣的是,*10 看起来更接近我想要的 - 但这对我来说意义不大,所以我对修复持谨慎态度。来自下面 fiddle 的相关 JS。感谢您的帮助。

var time = 0;
var rad_tick = (Math.PI*2)/2560; //radians per tick: last number is ms per revolution

// Draw Clock
const clock = document.getElementById('clock')
const clock_ctx = clock.getContext('2d')
clock_ctx.translate(clock.width/2, clock.height/2);
radius = (clock.height/2) * 0.7;

function drawClock() {
    clock_ctx.clearRect(-clock.width/2, -clock.height/2, clock.width, clock.height);
    clock.style.backgroundColor = 'transparent'; 
    clock_ctx.beginPath();
    clock_ctx.arc(0, 0, radius, 0 , 2 * Math.PI);
    clock_ctx.stroke();
}

drawClock();

// Draw Hand
const hand = document.getElementById('hand')
const hand_ctx = hand.getContext('2d')
hand_ctx.translate(hand.width/2, hand.height/2);

function drawHand(time){
    hand_ctx.clearRect(-hand.width/2, -hand.height/2, hand.width, hand.height);
    hand_ctx.beginPath();
    hand_ctx.moveTo(0,0);
    hand_ctx.rotate(time);
    hand_ctx.lineTo(0, -radius*0.9);
    hand_ctx.stroke();
    hand_ctx.rotate(-time);
}

function drawTime(){
    time+=rad_tick;//*10
    drawHand(time)
}

var intervalId = setInterval(drawTime, 1);

您要求 setInterval 每 1 毫秒调用一次回调,但 实际上 每 1 毫秒调用一次吗?

试试这个代码:

let cnt = 0;
setInterval(() => cnt++, 1);
setTimeout(() => { console.log(cnt); }, 1000);

对我来说,它打印的时间介于 230 和 235 之间。所以看起来实际(平均)最小间隔对我来说有点超过 4 毫秒。

加上 Stig,由于 javascript 在这些方面不是非常快,所以它不会非常准确。使用 getTime() 之类的东西将允许适当的时间。你如何在 drawTime 函数中调用 getTime,这样 around 每毫秒,它会检查实际时间并使用该值。

以当前时间为基础,不要依赖于 setInterval 在您将其设置为触发的确切时间触发。如果在 setInterval 应该触发时有事情 in-queue,它将首先做这些事情 in-queue 然后才 运行 你连接到 setIterval 的函数(导致延迟你看——随着时间的推移越来越多)。了解 event loop and requestAnimationFrame.

相反,在做某事之前(新鲜地)获取时间,并计算自开始时间以来经过了多少时间。将您的动画基于这些计算。这样,即使有轻微的延迟,您的最后一个操作也会始终将它们同步到它们现在应该看起来的样子。

当您这样做时,您可能会丢失一些帧(跳过引擎没有时间做的事情),但它可能会在更接近预期完成时间的情况下完成。

底线是,如果您告诉浏览器在特定时间内做的事情超过它可以做的事情,就会出现延迟。但是,您可以跳过动画的帧,使事情更接近预期的完成时间。

试试这个

var starttime = new Date().getTime();

function drawTime() {
    var elapsed = new Date().getTime() - starttime;
    var time = elapsed % 2560;
    time = time * rad_tick;
    console.log(elapsed + "->" + time);
    drawHand(time)
}