Search code examples
javascriptcssrequestanimationframe

Infinit clockwise rotation using js and css - difference between timeout(0) and requestAnimationFrame()


I have an element which rotates depending on a value between 0 and 3. The rotation has a transition and it always should turn clockwise. The value will be set to minvalue if the maxvalue is overflow but the transition on reset will turn counterclockwise.

My idea was to set the value to -1 and disabling transition. After one animation frame, enabling transition and set value to 0, so it will rotate clockwise.

requestAnimationFrame does not work but setTimeout with 0 milliseconds work. What is the difference between requestAnimationFrame and setTimeout?

function rotateAnimation(){
  let cb = rotate();
  cb && window.requestAnimationFrame(cb);
}

function rotateTimeout(){
  let cb = rotate();
  cb && window.setTimeout(cb,0);
}

function rotate(){
  let rotate = document.querySelector(".rotate");
  let value = ++rotate.dataset.value % 4;
  let cb = null;
  if(value === 0){
    rotate.style.setProperty("transition", "none");
    value = -1;
    cb = () => {
      rotate.style.removeProperty("transition");
      rotate.style.setProperty("--value", "0");
    };
  }
  rotate.style.setProperty("--value", value);
  return cb;
}
.rotate {
  display: inline-block;
  transition: transform 0.2s linear;
  transform: rotate(calc(var(--value, 0) * 90deg));
}
<div class="rotate" data-value="0">Rotate</div>
<button onclick="rotateAnimation()">rotate - reset by animation frame</button>
<button onclick="rotateTimeout()">rotate - reset by timeout</button>


Solution

  • The difference

    As mentioned in MDN

    The window.requestAnimationFrame() method tells the browser that you wish to perform an animation and requests that the browser calls a specified function to update an animation before the next repaint.

    And a mozilla blog post explains

    Since the interval parameter is irrelevant in complex animations, as there’s no guarantee that it will be honored, a new API has been designed: requestAnimationFrame. It’s simply a way to tell the browser “before drawing the next frame on the screen, execute this game logic/animation processing”. The browser is in charge of choosing the best moment to execute the code, which results in a more efficient use of resources.

    So the difference simply is the guarantee to make the best timing for your frame to achieve the most frame rate possible!

    For more description we should say that setTimeout(fn, 0) is to make a asynchronous callback as soon as possible and doesn't care about painting and render!

    But Window.requestAnimationFrame(fn) just cares about painting and will execute all callbacks before next frame painting!

    Best solution

    Don't bother your self with numbers let the CSS do the job for you for free!

    function rotate(){
      let rotate = document.querySelector(".rotate");
      let value = ++rotate.dataset.value;
      rotate.style.setProperty("--value", value);
    }
    .rotate {
      --value: 0;
      display: inline-block;
      transition: transform 0.2s linear;
      transform: rotate(calc(var(--value) * 90deg));
    }
    <div class="rotate" data-value="0">Rotate</div>
    <button onclick="rotate()">rotate</button>