Что именно является аргументом в обратном вызове requestAnimationFrame? - PullRequest
0 голосов
/ 13 мая 2018

Просто запустите это:

function requestAndDraw() {
  requestAnimationFrame((t) => {
    console.log(`T: ${t} P.now:${performance.now()}`);
  });
}

intId = setInterval(requestAndDraw, 20);
setTimeout(() => clearInterval(intId), 1000);

Он печатает что-то вроде этого:

T: 1164.656 P.now:1176.300000000083

Интересно, в чем причина разницы в 12 мс? Потребовалось некоторое время, чтобы выполнить некоторые другие обратные вызовы, зарегистрированные с requestAnimationFrame? Это просто накладные расходы, связанные с интерпретацией JS? или что? 12мс - это не то, что я выбрасывал бы в этом контексте.

1 Ответ

0 голосов
/ 13 мая 2018

Аргументом является DOMHighResTimeStamp , точно так же, как Performance.now должен возвращаться, даже если это не тот, который возвращается этим методом.


Итак, сначала давайте объясним разницу в точности, которую вы видите: недавно была обнаружена серьезная проблема безопасности в большинстве процессоров, известных под именами Meltdown и Spectre .
Эти атаки могут быть выполнены из веб-браузера, но для этого требуется DOMHighResTimeStamp , возвращаемый Performance.now . Firefox обнаружил, что быстрое решение проблемы «смягчения» заключалось в снижении разрешения этого DOMHighResTimeStamp . (см. Подробнее).

Поскольку requestAnimationFrame запланированы обратные вызовы для запуска следующего кадра (т. Е. ~ 16 мс после предыдущего вызова), DOMHighResTimeStamp, переданный из этого метода, не требует этого смягчения , следовательно, у вас все еще есть полная точность в this DOMHighResTimeStamp .


Теперь, чтобы ответить на вопрос заголовка, DOMHighResTimeStamp, переданный в обратных вызовах requestAnimationFrame, представляет время вызова стека всех обратных вызовов для этого кадра.
Действительно, requestAnimationFrame сохраняет только параметр обратного вызова в стеке, и этот стек затем вызывается, когда происходит кадр (непосредственно перед следующей операцией painting ).
Это означает, что все обратные вызовы для одного и того же кадра будут использовать один и тот же DOMHighResTimeStamp , независимо от того, сколько времени занимал предыдущий обратный вызов.

function long(time){
  var now = performance.now();
  console.log('long');
  console.log({
    'rAF time': time,
    'Performance time': now,
    'diff': (now - time) + 'ms'
  });
  console.log('________________________');
  // wait 50ms
  while(performance.now() - time < 50) {
  }
}
function short(time) {
  var now = performance.now();
  console.log('short');
  console.log({
    'rAF time': time,
    'Performance time': now,
    'diff': (now - time) + 'ms'
  });
}
// our two functions will be stacked together to fire in the same frame
requestAnimationFrame(long);
requestAnimationFrame(short);
...