performance.now() called before requestAnimationFrame - performance.now() has a larger t
Asked Answered
C

2

4

So I have a simple function:

var start = function(){

    lastFrame = performance.now();


    requestAnimationFrame((t)=>{interval(t)});


}

And my interval function (just for test purposes I have clogged the values of each rAF stamp)

function interval(t){
    console.log (t);
    console.log(lastFrame);
}

Now I have read the following response to another question but I just can't understand a few parts of this person's answer.

The timestamp passed in to the requestAnimationFrame() callback is the time of the beginning of the animation frame. Multiple callbacks being invoked during the same frame all receive the same timestamp. Thus, it would be really weird if performance.now() returned a time before the parameter value, but not really weird for it to be after that.

"it would be really weird if performance.now() returned a time before the paramter value" ?

Why would this be weird? I thought Javascript was an interpreted language? At this point:

lastFrame = performance.now();

The browser doesn't even now about the next line:

requestAnimationFrame((t)=>{interval(t)});

Surely if you make a call to performance.now() before you even provide a callback for your requestAnimationFrame the time of lastFrame should be less than the t passed into requestAnimationFrame?

In this person's response, he lays out a 6 step process involved with requesting an animation frame. However, he lists the performance.now() call as the last step.

How can it be the last step when it has been interpreted by the browser before the animationFrame request?

Cofield answered 9/2, 2017 at 10:31 Comment(1)
He is talking about calling performance.now from inside the interval function, not from start.Coventry
R
3

The answer you Pointyed to talks about calling performance.now() inside the callback of rAF. You are calling it outside, so of course, it will be set to a date before.


Your code, simplified.

let t0 = performance.now(); // This is called now

requestAnimationFrame(t1=>func(t1)); // this will be called at next screen refresh
                                     // (somewhere between 0 and 17 ms later)

The other answer's Pointy:

let f1 = time => {
  window.calledTime = time;
  while(wait(a_few_seconds)){}
  }
let f2 = time => {
  time === window.calledTime; // true !
  performance.now() - time; // approximately a_few_seconds
  }
requestAnimationFrame(f1);
requestAnimationFrame(f2);

So with a few words, let's say that in your case it's normal that lastFrame is set before t, since it is called way before (rAF is async).
The other answer talked about chained rAF calls, which are all stacked in a same function call, and thus will all share the same timestamp argument, whatever the time previous callback took to execute.


Now, if what you need is an original timestamp, you're quite safe using performance.now() as a fallback, since it's similar to what is sent as argument to your callback, except that it reflects the time when the monitor sent its last V-Sync pulse, and is thus common to all callbacks of the same frame.

const loop = time => { 
  if(!time) time = performance.now(); // we called it out of a rAF routine
  ...
  requestAnimationFrame(loop)
}
loop();

However, if you are using an rAF loop, most of the time, it's because you need your routine to be in sync with the screen. So it makes more sense to wait until the next screen refresh before starting your loop, otherwise, you'd execute this routine twice in a single frame.

const loop = time =>{
    ...
  }
requestAnimationFrame(loop); // call it directly through rAF
Rhonarhonchus answered 29/4, 2017 at 9:22 Comment(3)
Hello, would you know the answer to this ? #43697331Polyanthus
You didn't answer to Surely if you make a call to performance.now() before you even provide a callback for your requestAnimationFrame the time of lastFrame should be less than the t passed into requestAnimationFrame?Detain
@ChangdaePark I didn't have to since OP did misread the other answer they linked to. They were not getting why the other answerer said it would be weird, because they missed that they were in a totally different configuration. This question has nothing to do with the fact that rAF timestamp may be set to a timestamp prior to the actual call (at least in Chrome buggy implementation). And I think you already saw the one question that deals with this case: #64177881Rhonarhonchus
H
3

I've also run into this. Seems like a bug, since it's so unintuitive.

I've resorted to using Date.now() for the initial value of elapsedTime.

var elapsedTime = 0;
var startTime = Date.now();
var lastTime = null;

requestAnimationFrame(update);

function update(currentTime) {
  if (lastTime) {
    elapsedTime += currentTime - lastTime;
  } else {
    elapsedTime = Date.now() - startTime;
  }

  // Compute the next value in the animation.
  var value = computeValue(elapsedTime);

  // Store the timestamp representing the animation frame.
  lastTime = currentTime;
}
Hartsell answered 29/4, 2017 at 5:40 Comment(0)
R
3

The answer you Pointyed to talks about calling performance.now() inside the callback of rAF. You are calling it outside, so of course, it will be set to a date before.


Your code, simplified.

let t0 = performance.now(); // This is called now

requestAnimationFrame(t1=>func(t1)); // this will be called at next screen refresh
                                     // (somewhere between 0 and 17 ms later)

The other answer's Pointy:

let f1 = time => {
  window.calledTime = time;
  while(wait(a_few_seconds)){}
  }
let f2 = time => {
  time === window.calledTime; // true !
  performance.now() - time; // approximately a_few_seconds
  }
requestAnimationFrame(f1);
requestAnimationFrame(f2);

So with a few words, let's say that in your case it's normal that lastFrame is set before t, since it is called way before (rAF is async).
The other answer talked about chained rAF calls, which are all stacked in a same function call, and thus will all share the same timestamp argument, whatever the time previous callback took to execute.


Now, if what you need is an original timestamp, you're quite safe using performance.now() as a fallback, since it's similar to what is sent as argument to your callback, except that it reflects the time when the monitor sent its last V-Sync pulse, and is thus common to all callbacks of the same frame.

const loop = time => { 
  if(!time) time = performance.now(); // we called it out of a rAF routine
  ...
  requestAnimationFrame(loop)
}
loop();

However, if you are using an rAF loop, most of the time, it's because you need your routine to be in sync with the screen. So it makes more sense to wait until the next screen refresh before starting your loop, otherwise, you'd execute this routine twice in a single frame.

const loop = time =>{
    ...
  }
requestAnimationFrame(loop); // call it directly through rAF
Rhonarhonchus answered 29/4, 2017 at 9:22 Comment(3)
Hello, would you know the answer to this ? #43697331Polyanthus
You didn't answer to Surely if you make a call to performance.now() before you even provide a callback for your requestAnimationFrame the time of lastFrame should be less than the t passed into requestAnimationFrame?Detain
@ChangdaePark I didn't have to since OP did misread the other answer they linked to. They were not getting why the other answerer said it would be weird, because they missed that they were in a totally different configuration. This question has nothing to do with the fact that rAF timestamp may be set to a timestamp prior to the actual call (at least in Chrome buggy implementation). And I think you already saw the one question that deals with this case: #64177881Rhonarhonchus

© 2022 - 2024 — McMap. All rights reserved.