2015-04-30 24 views
8

Cách tốt nhất để nhận chênh lệch thời gian giữa lệnh gọi lại "window.requestAnimationFrame" trong javascript là gì?Javascript: Cách nhận chênh lệch thời gian giữa window.requestAnimationFrame

Tôi đã thử:

// 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? 
+1

tiềm năng trùng lặp: http://stackoverflow.com/questions/8279729/calculate-fps-in-canvas- sử dụng-requestanimationframe –

+0

Khá chắc chắn rằng cuộc gọi lại được chuyển một tham số, dấu thời gian (trong yêu cầu fullAnAnationFrame gốc đầy đủ) nếu bạn đang tìm hỗ trợ cho polyfill, có những tham số mô phỏng tham số dấu thời gian tốt hơn thông số bạn có window.FPS polyfill. [Điều này] (https://gist.github.com/timhall/4078614) có lẽ là một trong những cái tốt hơn tôi đã nhìn thấy. Liên quan đến [this] (http://stackoverflow.com/questions/13241314/up-to-date-polyfill-for-requestanimationframe) SO câu hỏi – OJay

+1

Btw, bạn hoàn toàn có thể bỏ qua IEFE và 'return' của nó, chỉ cần gán' window.raf =… || … || chức năng (cb) {…}; ' – Bergi

Trả lời

2

Hầu hết các trình duyệt hiện đại tự động gửi một dấu thời gian chính xác cao như một đối số vào mỗi vòng lặp requestAnimation callback: http://caniuse.com/#search=performance

Vì vậy, bạn chỉ đơn giản là trừ dấu thời gian cuối cùng từ timestamp hiện tại để có được thời gian trôi qua kể từ khi vòng lặp được chạy lần cuối.

Dưới đây là ví dụ mã và một Demo:

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>

Đối với vài trình duyệt không hỗ trợ Performance, bạn sẽ phải sử dụng Date.now() thay vì currentTime bên trong vòng lặp vì không có dấu thời gian được tự động gửi bởi các trình duyệt đó vào vòng lặp.

+0

'parseInt' làm gì ở đó? Là một người giữ huy hiệu vàng js bạn nên biết rõ hơn! – Bergi

+0

@Bergi. Chuckle, đồng ý! – markE

4

có "dt" độ chính xác tốt nhất?

số Theo the docs,

Phương pháp gọi lại được thông qua một đối số duy nhất, một DOMHighResTimeStamp, mà chỉ ra thời điểm hiện tại khi callbacks xếp hàng bởi requestAnimationFrame bắt đầu bắn

vì vậy bạn nên sử dụng nó để có được độ chính xác cao.

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)

+0

Cũng đáng chú ý là dấu thời gian rAF sẽ được lượng tử hóa trong bất kỳ trường hợp nào thành 16,67ms, 16,67x2 vv vì nó được đồng bộ hóa với tốc độ làm tươi màn hình. – K3N

+0

var last = now || Date.now() là sai tôi nghĩ. "now" là dấu thời gian kể từ khi animationFrame bắt đầu, trong khi Date.now() là dấu thời gian Unix – marirena

+0

@marirena: Không, 'now'" * cho biết thời gian hiện tại * "theo tài liệu chứ không phải thời gian từ khi yêu cầu rAF. Đó là dấu thời gian mili giây tuyệt đối giống như 'Ngày.bây giờ', nhưng với độ chính xác cao hơn (và có thể là một nguồn gốc khác). Bạn hoàn toàn có thể bỏ qua '|| ... 'một phần là tốt, nó chỉ là một dự phòng cho shims không tương thích rAF. – Bergi

2

tôi sẽ viết một kết luận rõ ràng, cho tất cả mọi người muốn sử dụng mô hình này

// 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

'(1/(dt/1000))' có thể được đơn giản hóa thành: '(1000/dt)'. Không biết tại sao bạn làm theo cách này. –

Các vấn đề liên quan