Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it true that if possible I should never use setInterval & setTimeout?

I am learning to code in JavaScript. I am programming something with some timed mouse animation. I'm just about to add some code which draws the mouse path.

It's going to be something that takes the mousemove event, and every time the mouse moves draw a new line path on Canvas. And with time, that path is going to be more transparent until it disappears. Of course, new paths are always going to be opaque so there's a continuous movement.

I figured out a way I can do this with just requestanimationframe. Basically every time a new mousemove event occurs, I will add that mouse path coordinates to an array of objects called mousePathArray. The object will carry the path coordinates and an "animationStage" counter. This counter will basically determine how transparent the path will be at that stage of the 'animation'. (Later stages will mean more transparent.)

Then every animation frame I will call a function that will go through all the objects in the array and draw the lines according to their coordinates and animationStage counter, will increase the counter by 1 and will remove the array objects if the animationStage counter reaches the end number (which could be 50 or something).

This can all be done, but it sounds like instead of all of that, it would be much easier to do by just introducing a setInterval function that will be called with a set interval every time the mouse moves.

So is it worth it doing the long way? Would it be faster or maybe just be better JS practice to not use setInterval and rAF together?

After writing all this down I actually wrote the rAF-only code that I talked about above. It's too long to paste here but the rules need it. Here it is on jsfiddle: http://jsfiddle.net/06f7zefn/2/

(I'm aware there are a lot of inefficiencies and probably terrible coding practice but bear with me, I'm 5 days old in this! I could make an isDrawing? boolean instead of calling animate() on every frame, and I can just do ctx.moveTo() once with the rest being LineTo() without having to to moveTo() every iteration since one point originates from where the other left off)

If I could get across the main idea I'm talking about, that is where I am asking for your opinion. Instead of making everything related to timing originate from the rAF call could it be better to use setInterval or setTimeout here instead?

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();
}
like image 453
irenicus Avatar asked Jun 09 '15 03:06

irenicus


People also ask

Is using setInterval bad?

In case of time intensive synchronous operations, setTimeInterval may break the rhythm. Also, if any error occurs in setInterval code block, it will not stop execution but keeps on running faulty code. Not to mention they need a clearInterval function to stop it.

Why is setInterval not accurate?

The real-time interval can only be greater than or equal to the value we passed. From the above code, we can see that setInterval is always inaccurate. If time-consuming tasks are added to the code, the difference will become larger and larger ( setTimeout is the same).

Should I use setInterval or setTimeout?

That's called “scheduling a call”. There are two methods for it: setTimeout allows us to run a function once after the interval of time. setInterval allows us to run a function repeatedly, starting after the interval of time, then repeating continuously at that interval.

Does setInterval affect performance?

This is unlikely to make much of a difference though, and as has been mentioned, using setInterval with long intervals (a second is big, 4ms is small) is unlikely to have any major effects.


1 Answers

I don't think using setInterval or setTimeout is bad practice. Using setTimeout is bad practice when you want to do something in the future, but you don't exactly know when you will be able to do that. For example, this is bad practice:

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

the correct way was:

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

If you want to do something in future like respond to a user action 100ms later, it's best practice to use setTimeout or if you want to put something in browser queue, you should use setTimeout (or use a worker if needed).

It's the same as setInterval, if you are using to do something that should be done every x milliseconds, well you are using it correctly and it's not bad practice, here is a bad usage of setInterval:

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

And here is a regular usage of setInterval:

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

Bad practices and good practices are defined by the way you use your environment tools, not the tools themselves.

like image 55
Iman Mohamadi Avatar answered Oct 14 '22 11:10

Iman Mohamadi