Производительность веб-приложений: когда миллисекунд недостаточно

Иногда точности измерения времени в миллисекундах недостаточно. Вместе с ведущими компаниями в отрасли и сообществом разработчиков рабочая группа консорциума W3C по стандарту Web Performance (Производительность веб-приложений) пыталась решить эту проблему, стандартизируя спецификацию High Resolution Time. На этой неделе данная спецификация была опубликована как Proposed Recommendation (PR) и теперь широко применяется в современных браузерах. Изучите демонстрацию What Time is it? (Сколько времени?), чтобы увидеть, как работает этот API.

Спецификация прошла путь от простой идеи до PR-версии всего за восемь месяцев. Этот этап стандартизации является заключительным шагом перед тем, как веб-стандарт становится официальной рекомендацией консорциума W3C (получает статус Recommendation). Кроме того, этот интерфейс начал широко применяться в браузерах, включая полную поддержку в Internet Explorer 10 и Firefox 15, а также поддержку с префиксом в Chrome 22. Это прекрасный пример того, что возможно, когда ведущие компании отрасли и сообщество работают вместе в W3C.

Так почему миллисекунд недостаточно? В течение долгого времени в веб-платформе время измерялось с помощью определенной формы JavaScript-объекта Date с помощью метода Date.now() или типа DOMTimeStamp. Объект Date представляет значение времени как время в миллисекундах с 1 января 1970 г. в формате UTC. Для большинства практических целей такое определение времени было достаточным для представления любого момента в течение 285 616 лет с 1 января 1970 г. (в формате UTC).

Например, на момент написания этого блога значение времени Date.now() из консоли IE10 Developer Tools было равно 1350509874902. Это число из тринадцати разрядов представляет число миллисекунд, прошедших с 1 января 1970 г. Это время соответствует 21:37:54 (UTC) 17 октября 2012 г.

Хотя это определение будет и дальше полезным для определения текущего календарного времени, в некоторых случаях его недостаточно. Например, для разработчиков будет полезно определить, плавно ли отображается анимация при частоте 60 кадров в секунду (один кадр отображается каждые 16,667 мс). Используя простой метод расчета частоты кадров путем измерения времени последнего обратного вызова рисования кадра, можно определить только частоту кадров до 58,8 кадров в секунду (1/17) или 62,5 кадров в секунду (1/16).

Разрешение с точностью до долей миллисекунды полезно также для точного определения прошедшего времени (например, при использовании API-интерфейсов Navigation Timing, Resource Timing и User Timing для создания функций определения времени в сети и скриптах) или для синхронизации сцен анимации или звука с анимацией.

Для решения этой проблемы в спецификации High Resolution Time определяется новое базовое время с микросекундным разрешением (одна тысячная миллисекунды). Чтобы сократить количество разрядов, используемых для представления этого числа, и улучшить читаемость, вместо измерения времени с 1 января 1970 г. этот новый формат измеряет время с начала просмотра документа (performance.timing.navigationStart).

В спецификации определяется метод performance.now(), аналогичный методу Date.now(), для определения текущего времени с высоким разрешением. DOMHighResTimeStamp — это аналогичный DOMTimeStamp тип, определяющий значение времени с высоким разрешением.

Например, узнав текущее время с помощью методов performance.now() и Date.now() в консоли IE10 Developer Tools в момент написания этого блога, я увидел два следующих значения:

 performance.now():        196.304879519774
Date.now():        1350509874902

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

Так как время в высоком разрешении измеряется с начала просмотра документа, performance.now() во вложенном документе будет измеряться с начала просмотра вложенного, а не основного документа. Предположим, в документе есть элемент iframe A с одним происхождением и элемент iframe B с другим происхождением, при этом просмотр начался в элементе iframe A приблизительно через 5 мс после начала просмотра основного документа, а в элементе iframe B — через 10 мс после начала просмотра основного документа. Если измерить точный момент времени через 15 мс после начала просмотра основного документа, мы получим следующие значения performance.now() в различных контекстах:

performance.now() в iframe B:                                5.123 мс

performance.now() в iframe A:                               10.123 мс

performance.now() в основном документе:                    15.123 мс

Date.now() в любом контексте:                         134639846051 мс

Рисунок, демонстрирующий отличие измерений времени с помощью Date.now() и performance.now()
Рис. Время Date.now() отсчитывается с 1 января 1970 г., а performance.now() — с начала просмотра документа

Это не только гарантирует, что на момент создания родительского объекта в элементах iframe различного происхождения не было утечки данных, но также позволяет измерять время относительно вашей точки отсчета. Например, если вы использовали интерфейс Resource Timing (на основе спецификации High Resolution Time), чтобы определить, сколько времени требуется серверу для ответа на запрос ресурса во вложенном документе, вам не потребуется вносить изменения для учета времени добавления вложенного документа в основной.

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

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

High Resolution Time является прекрасным примером того, насколько быстро новые идеи могут стать совместимыми стандартами, на которые разработчики могут опираться в современных браузерах с поддержкой HTML5. Благодарим всех участников рабочей группы консорциума W3C по стандарту Web Performance за помощь в создании этого API и других поставщиков браузеров за быструю его реализацию для обеспечения совместимости.

Спасибо за внимание!
Джатиндер Манн (Jatinder Mann)
Руководитель программы, Internet Explorer