2016-07-13 13 views
3

Предположения: rAF now Время рассчитывается во время запуска всех обратных вызовов. Поэтому любая блокировка, которая происходит до первого обратного вызова этого фрейма, не влияет на rAF now, и это точно - по крайней мере, для этого первого обратного вызова.requestAnimationFrame [now] vs performance.now() time discrepancy

Любые измерения performance.now(), сделанные до запуска rAF-набора, должны быть раньше, чем rAF now.

Тест: Запись before (базовое время до ничего бывает). Установите следующий rAF. Сравните rAF now и введите номер телефона performance.now(), чтобы узнать, насколько отличаются.

Ожидаемые результаты:

var before = performance.now(), frames = ["with blocking", "with no blocking"], calls = 0; 
 
requestAnimationFrame(function frame(rAFnow) { 
 
    var actual = performance.now(); 
 
    console.log("frame " + (calls + 1) + " " + frames[calls] + ":"); 
 
    console.log("before frame -> rAF now: " + (rAFnow - before)); 
 
    console.log("before frame -> rAF actual: " + (actual - before)); 
 

 
    if (++calls < frames.length) { before = actual; requestAnimationFrame(frame); } 
 
}); 
 

 
// blocking 
 
for (var i = 0, l = 0; i < 10000000; i++) { 
 
    l += i; 
 
}

Наблюдения: Когда происходит блокирование до начала кадра, время RAF now порой неправильно, даже для этого первого кадра. Иногда первый кадр now на самом деле является более ранним временем, чем записанное время before.

есть ли преграждает происходит перед кадром или нет, каждый так часто в кадре время rAFnow будет раньше времени до кадра before --Но, когда я настроить RAF после я беру первое измерение , Это также может произойти без каких-либо блокировок, хотя это реже.

(я получаю ошибку синхронизации на первом блокирующем кадре большую часть времени. Getting вопрос о других встречается реже, но иногда случается, если вы попытаетесь запустить его несколько раз.)

С более обширным тестирование, я обнаружил плохие времена с блокировкой до обратного вызова: 1% от 100 кадров, без блокировки: 0.21645021645021645% от ~ 400 кадров, что, по-видимому, вызвано открытием окна или некоторым другим потенциально интенсивным действием процессора.

Так что это довольно редко, но проблема в том, что это не должно происходить вообще. Если вы хотите делать с ними полезные вещи, имитируя время, анимацию и т. Д., То вам нужны эти времена, чтобы иметь смысл.

Я принял во внимание то, что сказали люди, но, возможно, я до сих пор не понимаю, как все работает. Если это все в спецификации, я бы хотел, чтобы какой-нибудь псевдо-код укрепил его в моем сознании.

И что еще более важно, если у кого-то есть предложения по поводу того, как я мог обойти эти проблемы, это было бы потрясающе. Единственное, что я могу придумать, это взять мой собственный performance.now() измерение каждого кадра и использовать его - но это кажется немного расточительным, если он эффективно запускается дважды в каждом кадре, поверх любых событий, вызванных событиями, и так далее.

+0

Я добавил состояние остановки в ваш фрагмент. Не стесняйтесь отката, но таким образом код на самом деле заканчивается в какой-то момент :). –

+0

Нет, это круто. Спасибо, @MikeMcCaughan. – Whothehellisthat

ответ

5

Временная метка, прошедшая с обратным вызовом requestAnimationFrame(), является временем начала анимационного кадра. Несколько обратных вызовов, вызываемых в течение одного и того же фрейма, получают одну и ту же метку времени. Таким образом, было бы действительно странно, если performance.now() вернуло время до значение параметра, но не очень странно, чтобы оно было после что.

Here's the relevant specification:

Когда агент пользователя для запуска анимации кадра обратного вызова для документа Документ с меткой времени Теперь, он должен выполнить следующие шаги:

  1. Если значение возвращенный скрытым атрибутом объекта документа, истинно, прервите эти шаги. [СТРАНИЦА-ВИДИМОСТЬ]

  2. Позволяет обратным вызовам быть списком записей в списке обратных вызовов фрейма в списке документов, в том порядке, в котором они были добавлены в список.

  3. Установить список обращений к списку анимации в пустой список.

  4. Для каждой записи в обратных вызовах, в порядке: вызовите функцию Web IDL обратного вызова, передавая Теперь в качестве единственного аргумента, и если исключение, сообщает исключение.

Так вы зарегистрировали обратный вызов (допустим только один) для следующего кадра анимации. Тик тик тик, БУМ, время для этого кадра анимации произойдет:

  1. Среда выполнения JavaScript делает отметку времени и этикетки, что сейчас.
  2. Среда выполнения создает временную копию списка зарегистрированных обратных вызовов обрамления анимации и очищает фактический список (чтобы они не были случайно вызваны, если что-то происходит так долго, что появляется следующий кадр анимации).
  3. В списке есть только одна вещь: ваш обратный вызов. Система вызывает, что с теперь в качестве параметра.
  4. Ваш обратный вызов начинает работать. Возможно, это никогда не запускалось раньше, поэтому оптимизатору JavaScript может потребоваться некоторая работа. Или, может быть, операционная система переключает потоки в какой-то другой системный процесс, например, запускает флеш диска или обрабатывает какой-то сетевой трафик или любой другой десяток других вещей.
  5. О, верно, ваш обратный вызов. Браузер снова запустит CPU, и ваш код обратного вызова начнет работать.
  6. Ваш код вызывает performance.now() и сравнивает его с Значение, переданное как параметр.

Поскольку кратко, но не игнорируемые количество времени может пройти между шагом 1 и 6, то возвращаемое значение из performance.now() может указывать, что пара микросекунд, или даже больше, чем пара, прошла. Это совершенно нормальное поведение.

+0

Вы говорите, что _any_ callback, даже не-rAF будут иметь одинаковое значение performance.now()? Кажется, это не так. Если вы имеете в виду несколько обратных вызовов rAF, я использую только один rAF. – Whothehellisthat

+0

Я сделал изменения, чтобы лучше объяснить, что происходит. (Я не был уверен, если вы получите уведомление?) – Whothehellisthat

+0

@Whothehellisthat нет нет нет. Когда событие происходит внутри среды выполнения JavaScript, которая запускает обработку обратных вызовов для фрейма анимации, отметка времени отмечается ** один раз ** в начале этого процесса. Каждый обратный вызов, зарегистрированный 'requestAnimationFrame()', передается точно таким же значением времени. Это действительно не имеет никакого отношения к последующим вызовам 'performance.now()', за исключением того, что они, очевидно, все будут * после *, что начальное время будет собрано. – Pointy

2

я столкнулся с таким же вопросом о хроме, где содержится призыв к performance.now() будет возвращать большее значение, чем now значения, переданного в последующие обратные вызовы, сделанных window.requestAnimationFrame()

моего обходным путем, чтобы установить before с помощью now передается в обратный вызов в первом window.requestAnimationFrame()довольно чем performance.now(). Кажется, что использование только одной из двух функций для измерения времени гарантирует прогрессирующее значение.

Я надеюсь, что это поможет кому-то еще страдать от этой ошибки.