【问题标题】:Javascript: How to get the time difference between window.requestAnimationFrameJavascript:如何获取 window.requestAnimationFrame 之间的时间差
【发布时间】:2015-04-30 02:07:21
【问题描述】:

在javascript中获取“window.requestAnimationFrame”回调之间的时间差的最佳方法是什么?

我试过了:

// create the best .requestAnimationFrame callback for each browser
window.FPS = (function() {
    return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame ||
    function(callback) {window.setTimeout(callback, 1000 / 60);};
})();

// start animation loop
var dt, stamp = (new Date()).getTime();
function loop() {
    window.FPS(loop);
    var now = (new Date()).getTime();
    var dt = now - stamp;
    stamp = now;
}
// has "dt" the best accuracy?

【问题讨论】:

  • 相当确定回调传递了一个参数,一个时间戳(在完整的本机 requestAnimationFrame 实现中),如果您正在寻找对 polyfill 的支持,那么有一些比什么更好地模拟时间戳参数你有你的 window.FPS polyfill。 This 可能是我见过的最好的之一。与this SO相关问题
  • 顺便说一句,您可以完全省略 IEFE 及其 return,只需分配 window.raf = … || … || function(cb){…};

标签: javascript canvas time frame-rate requestanimationframe


【解决方案1】:

大多数现代浏览器会自动将高精度时间戳作为参数发送到每个 requestAnimation 回调循环中:http://caniuse.com/#search=performance

因此,您只需从当前时间戳中减去最后一个时间戳,即可获得自上次运行循环以来经过的时间。

这是示例代码和演示:

var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;

var startingTime;
var lastTime;
var totalElapsedTime;
var elapsedSinceLastLoop;

var $total=$('#total');
var $loop=$('#loop');

requestAnimationFrame(loop);

function loop(currentTime){
  if(!startingTime){startingTime=currentTime;}
  if(!lastTime){lastTime=currentTime;}
  totalElapsedTime=(currentTime-startingTime);
  elapsedSinceLastLoop=(currentTime-lastTime);
  lastTime=currentTime;
  $total.text('Since start: '+totalElapsedTime+' ms');
  $loop.text('Since last loop: '+elapsedSinceLastLoop+' ms');
  requestAnimationFrame(loop);
}
body{ background-color: ivory; }
#canvas{border:1px solid red;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<p id=total>T1</p>
<p id=loop>T2</p>
<canvas id="canvas" width=300 height=300></canvas>

对于不支持Performance 的浏览器,您必须在循环内使用Date.now() 而不是currentTime,因为这些浏览器不会自动将时间戳发送到循环中。

【讨论】:

  • parseInt 在那里做什么?作为一个js金徽章持有者你应该更了解!
  • @Bergi。轻笑,同意!
【解决方案2】:

“dt”的准确度最高吗?

没有。根据the docs

回调方法被传递了一个参数,DOMHighResTimeStamp,它表示由requestAnimationFrame 排队的回调开始触发的当前时间

所以你应该使用它来获得高精度。

function loop(now) {
    var last = now || Date.now(); // fallback if no precise time is given
    window.FPS(function(now) {
        now = now || Date.now();
        var dt = now - last;
        if (dt != 0) // something might be wrong with our frames
             console.log(dt);
        loop(now);
    });
}
window.FPS(loop);

(jsfiddle demo)

【讨论】:

  • 另外值得注意的是,rAF 时间戳在任何情况下都会被量化为 16.67 毫秒、16.67x2 等,因为它与显示器刷新率同步。
  • var last = 现在 ||我认为 Date.now() 是错误的。 "now" 是 animationFrame 开始以来的时间戳,而 Date.now() 是 Unix 时间戳
  • @marirena: 不,now表示当前时间”根据文档,而不是自调用 rAF 以来的时间跨度。与Date.now 一样,它是一个绝对毫秒时间戳,但精度更高(可能来源不同)。您也可以完全省略 || … 部分,这只是不兼容的 rAF 垫片的后备。
  • 我只是用 console.log(now) 运行它,“now”在开始时读取 0,每秒增加 1000
  • @marirena:正如我所说。它可能起源于页面加载而不是 1970 年 1 月 1 日,但它仍然是毫秒时间戳。而且由于我们只关心增量,所以来源并不重要。
【解决方案3】:

我会写一个明确的结论,给所有想用这个模式的人

// CREATING AN FPS ENGINE

window.FPS = (function() {
    return window.requestAnimationFrame ||
    window.webkitRequestAnimationFrame ||
    window.mozRequestAnimationFrame ||
    window.oRequestAnimationFrame ||
    window.msRequestAnimationFrame ||
    function(callback) {window.setTimeout(callback, 1000 / 60);};
})();

var FPS = {
    loop: function(canvas_object) { // OPTIONAL canvas_object, I think it increases performance | canvas_object = document.getElementById("canvas_id")
        var ticks = window.FPS(function(now){
            var dt = now - FPS.stamp || 0;
            FPS.stamp = now;
            FPS.update(dt, FPS.stamp, ticks);
            FPS.loop(canvas_object);
        }, canvas_object);

    },
    update: undefined,
    stamp: undefined
};

// USING THE FPS ENGINE

FPS.loop(the_canvas_object); // starts the engine
FPS.update = function(dt, stamp, ticks) {
    // The game/video loop, using accurate dt. Stamp is the time since engine started. Ticks is the number of the loop cycles
    console.log("dt: " + dt + ", Stamp: " + stamp + ", Ticks: " + ticks); // check output   
    // HAPPY GAME CREATING
    var fps= (1 / (dt / 1000)).toFixed(1);
};

【讨论】:

  • (1 / (dt / 1000)) 可以简化为:(1000 / dt)。不知道你为什么这样做。
猜你喜欢
  • 2014-02-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-28
  • 2014-06-11
  • 2021-07-31
  • 1970-01-01
相关资源
最近更新 更多