#javascript #html #canvas #requestanimationframe
Вопрос:
Просто запустите это:
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. Он регистрирует для меня точно такие же значения (я только что отредактировал ваш вопрос с помощью запущенной демо-версии, нажмите «запустить фрагмент кода»). Кроме того, вопрос в названии вашего вопроса и вопрос в тексте вашего вопроса не совпадают, вы задаете здесь два разных вопроса. Ответ на название может быть таким: developer.mozilla.org/en-US/docs/Web/API/DOMHighResTimeStamp
2. В каком браузере это происходит? Я не получаю такого же поведения, разница только ~1 мс в Chrome v66
3. Что касается моего браузера — Chrome v66/Ubuntu 18.04. Так что это как-то странно. Что касается вопроса — в следующий раз я буду менее общим в названии вопроса. И я не знал о функции «Запустить фрагмент кода» — спасибо за редактирование. Также… Когда я запускаю этот фрагмент, я получаю ту же разницу в 1 мс, но когда я копирую-вставляю его в консоль DevTools, я получаю эти 12 мс — похоже, это причина для другого вопроса) Хотя не знаю, как это назвать)
Ответ №1:
Аргумент представляет собой метку времени DOMHighResTimeStamp, точно так же, как и то, что Performance.now должен возвращать, даже если это не тот, который возвращается этим методом.
Итак, сначала позвольте объяснить разницу в точности, которую вы видите: недавно в большинстве процессоров была обнаружена серьезная проблема безопасности, известная под именами Meltdown и Spectre.
Эти атаки могут быть совершены из веб-браузера, но для этого требуется метка DOMHighResTimeStamp, возвращаемая Performance.now. Быстрое исправление / «смягчение», как обнаружил Firefox, заключалось в снижении разрешения этой метки времени. (см. Подробнее).
Поскольку обратные вызовы requestAnimationFrame запланированы для запуска следующего кадра (т. е. ~16 мс после предыдущего вызова), метка DOMHighResTimeStamp, переданная из этого метода, не требует этого смягчения, следовательно, у вас все еще есть полная точность в этой метке DOMHighResTimeStamp.
Теперь, чтобы ответить на вопрос заголовка, метка DOMHighResTimeStamp, переданная в requestAnimationFrame
обратных вызовах, представляет время вызова стека всех обратных вызовов для этого кадра.
Действительно, requestAnimationFrame хранит параметр обратного вызова только в стеке, и этот стек затем вызывается при появлении кадра (непосредственно перед следующей операцией рисования).
Это означает, что все обратные вызовы для одного и того же кадра будут иметь одну и ту же метку времени, независимо от того, сколько времени занял предыдущий обратный вызов.
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);