首页 > 解决方案 > requestAnimationFrame 在被函数调用之前运行

问题描述

我正在尝试使用 JavaScript 和 requestAnimationFrame 制作一个简单的计时器(从 0 开始计数)。单击某些内容时,我想从 0 开始计时器。目前,我的代码在单击按钮时显示计时器,但在我看来,requestAnimationFrame 甚至在函数被调用之前就已运行。如果您在网页上加载代码并等待几秒钟,然后单击按钮,您将看到计时器不是从 0 开始,而是从第一次加载页面以来的秒数开始。我不知所措,谷歌搜索并没有帮助我弄清楚计时器在调用函数之前为什么/如何开始计数。

我当前的代码:

<div class="time">
  Time: <label id="labelTime"></label>
</div>
<button id="button">Click me</button>
<script>
  const button = document.getElementById('button');
  button.addEventListener('click', clickButton);

  function clickButton() {
    runTimer();
  }

  function runTimer() {
    let rAF_ID;

    let rAFCallback = function(callback) {
      let count = callback;

      let s = Math.floor((count / 1000) % 60).toString().padStart(2, '0');
      let m = Math.floor((count / 60000) % 60);

      document.getElementById('labelTime').innerHTML = m + ":" + s;
      rAF_ID = requestAnimationFrame(rAFCallback);
    }
    rAF_ID = requestAnimationFrame(rAFCallback);
  }
</script>

标签: javascript

解决方案


传递给你的函数的timestamp( ) 值不是从动画第一次运行时开始的,而是它有一个“时间原点”,它因上下文而异。DOMHighResTimeStamprAFCallback

https://developer.mozilla.org/en-US/docs/Web/API/DOMHighResTimeStamp

  • 如果脚本的全局对象是 a Window,则时间原点确定如下:

    • 如果当前Document是在 中加载的第一个Window,则时间原点是创建浏览器上下文的时间。
    • 如果在卸载窗口中加载的上一个文档的过程中,显示​​一个确认对话框让用户确认是否离开上一个页面,时间原点是用户确认导航到新页面是可以接受的。
    • 如果以上都不能确定时间原点,则时间原点是负责创建窗口当前文档的导航发生的时间。
  • 如果脚本的全局对象是 WorkerGlobalScope(即脚本作为 web worker 运行),则时间原点是 worker 创建的时刻。
  • 在所有其他情况下,时间原点是未定义的。

因此,如果您想从动画开始时获取增量时间值,您需要自己执行此操作,如下所示:

let timestampAtStart = null;
let lastRequestId    = null;

function myAnimateFunction( timestamp ) {
    if( !timestampAtStart ) {
        timestampAtStart = timestamp;
    }

    let timeSinceStart = timestamp - timestampAtStart;

    console.log( timeSinceStart );

    lastRequestId = window.requestAnimationFrame( myAnimateFunction );
}

function startAnimation() {

    if( lastRequestId ) window.cancelAnimationFrame( lastRequestId );

    timestampAtStart = null;

    lastRequestId = window.requestAnimationFrame( myAnimateFunction );
}

推荐阅读