提问者:小点点

如果可能的话,我真的不应该使用setInterval吗


我正在学习用JavaScript编码。我正在用一些定时鼠标动画编程。我正要添加一些绘制鼠标路径的代码。

这将是一个获取mousemove事件的东西,每次鼠标移动都在画布上绘制一个新的线条路径。随着时间的推移,这条道路将变得更加透明,直到它消失。当然,新的路径总是不透明的,所以有一个连续的运动。

我想出了一个方法,只需要requestanimationframe就可以做到。基本上每次新的mousemove事件发生时,我都会将鼠标路径坐标添加到一个名为mousePathArray的对象数组中。该对象将携带路径坐标和一个“animationStage”计数器。这个计数器基本上决定了路径在“动画”阶段的透明度。(后期将意味着更加透明。)

然后,每一个动画帧我都会调用一个函数,该函数将遍历数组中的所有对象,并根据它们的坐标和animationStage计数器绘制线,将计数器增加1,如果animationStage计数器达到结束编号(可能是50或更多),则会删除数组对象。

这一切都可以完成,但听起来不是所有这些,而是通过引入一个setInterval函数来更容易做到,该函数将在每次鼠标移动时以设置的间隔调用。

那么值得长期这样做吗?不一起使用setInterval和rAF会更快还是更好的JS练习?

写下所有这些之后,我实际上写了上面提到的仅rAF代码。粘贴在这里太长了,但规则需要它。这里是jsfiddle:http://jsfiddle.net/06f7zefn/2/

(我知道有很多低效率和可能糟糕的编码实践,但请耐心等待,我在这方面已经5天了!我可以制作一个isDrawing?布尔值,而不是在每一帧上调用动画(),我可以只做一次ctx. moveTo(),其余的是LineTo(),而不必移动到()每次迭代,因为一个点来自另一个点停止的地方)

如果我能理解我所说的主要思想,那就是我征求你意见的地方。与其让所有与计时相关的东西都源自rAF调用,不如在这里使用setInterval或setTimeout?

var canvas = document.createElement('canvas');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
document.body.appendChild(canvas);

var ctx = canvas.getContext('2d');

var currentPosX, currentPosY, prevPosX, prevPosY;
var mousePathArray = [];

canvas.addEventListener ('mousemove', mouseOp);


function mouseOp (mouseEvent) {
    prevPosX = currentPosX;
    prevPosY = currentPosY;
    currentPosX = mouseEvent.clientX;
    currentPosY = mouseEvent.clientY;
    mousePathArray.push( {
        x1: currentPosX,
        x2: prevPosX,
        y1: currentPosY,
        y2: prevPosY,
        animStage: 0
    });
}

function animate () {
    var anims = mousePathArray.length;
    if (anims!=0) {
        for (i=0; i<anims; i++) {
            if (mousePathArray[i].animStage == 20) {
                mousePathArray.splice(i, 1);
                i--;
                anims--;
                continue;
            }

            drawLine(mousePathArray[i].x1, mousePathArray[i].x2, mousePathArray[i].y1, mousePathArray[i].y2, 1 - (mousePathArray[i].animStage * 0.05));
            mousePathArray[i].animStage ++;
        }
    }
}

function drawLine (x1, x2, y1, y2, alpha) {
    ctx.beginPath();
    ctx.moveTo(x1, y1);
    ctx.lineTo(x2, y2);
    ctx.strokeStyle = "rgba(150, 20, 150," + alpha +")";
    ctx.stroke();
}

animloop();

function animloop(){
  window.requestAnimationFrame(animloop);
  gameLoop();
}

function gameLoop() {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    animate();
}

共3个答案

匿名用户

我不认为使用setIntervalsetTimeout是不好的做法。当你想在将来做某事时,使用<code>setTimeout</code>是不好的做法,但你不知道什么时候能做到。例如,这是不好的做法:

makeHeavyDomMovements();
setTimeout(function () {
  //with 3000 timeout I'm sure any device has made my changes
  makeNextMove();
}, 3000);

正确的方法是:

makeHeavyDomMovements().
then(function () {
   makeNextMove();
});

如果您想在未来做一些事情,比如在100毫秒后响应用户操作,最好使用< code>setTimeout,或者如果您想在浏览器队列中放置一些东西,您应该使用< code>setTimeout(或者如果需要,使用一个worker)。

它与setInterval相同,如果您使用的是每x毫秒应该完成的事情,那么您使用它是正确的,这不是不好的做法,这里是setInterval的一个不好的用法:

var dbInterval = setInterval(function () {
  if (dbIsReady()) {
    clearInterval(dbInterval);
    fireReadyEvent();
  }
}, 300);

下面是< code>setInterval的常规用法:

setInterval(function () {
  runSync();
}, 600000);

坏的实践和好的实践是由您使用环境工具的方式来定义的,而不是工具本身。

匿名用户

Luz Caballero很好地描述了为什么rAF是setInterval的有用替代品:

https://dev . opera . com/articles/better-performance-with-request animation frame/。

至于我,我现在使用rAF而不是setInterval,因为rAF有一些内置的有用性,需要使用setInterval进行额外的编码:

>

  • rAF将尝试将其调用与显示刷新周期同步。这为循环中的代码提供了在刷新周期之间完成的“最佳机会”。

    如果在请求循环#2之前,循环#1中的任务无法完成,则在完成不完整的循环#1之前,不会调用新的循环#2。这意味着浏览器不会因积压的循环而过度工作。

    如果用户切换到不同的浏览器标签,则当前标签中的循环被挂起。这允许处理能力转移到新的选项卡,而不是在现在不可见的循环抽头中使用。这也是电池供电设备的省电功能。如果你想让循环在一个标签没有焦点的时候继续处理,你必须使用setInterval。

    rAF 回调函数自动获取高精度时间戳参数。这允许 rAF 环路计算

  • 匿名用户

    如果你100%确定这是你需要你的确切时间,你可以使用它们。如果这是一个模棱两可的情况,那就不要使用它。如果你使用的是javascript框架,请寻找生命周期挂钩,例如角使用角生命周期挂钩。