Получение времени окончания теста в замерах скорости браузеров

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

Суть в том, что при проведении замеров времени нужно, чтобы браузер отобразил результат на экране перед окончанием теста, то есть перед вторым чтением временной метки.

Проясним ситуацию с помощью примера. Тест скорости работы DOM может выглядеть приблизительно так:

function testIt() {
  var startTime = new Date().getTime();
 
  // Здесь находится тестируемый код DOM
 
  var endTime = new Date().getTime();
  var result = (endTime-startTime)/1000;
  // Вывод результата
}

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

Вот, что на самом деле здесь происходит:

1. Получение времени начала теста.
2. Манипуляция с DOM в памяти браузера.
3. Получение времени окончания теста и вычисление результата.
4. Выход из функции, только теперь браузер начинает отображать результаты изменений в DOM.

Не все браузеры ждут окончания работы функции для применения изменений, но некоторые так и поступают, и среди них Safari для iPhone 2.2. В таких браузерах будет измерено лишь время, необходимое для построения нового DOM-дерева в памяти, а время, затраченное на отображение, учтено не будет.

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

Для правильного проведения таких тестов необходимо устанавливать задержку перед считыванием времени окончания. Функция завершит выполнение после окончания работы с DOM в памяти и позволит браузеру применить сделанные изменения.

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

function testIt() {
  var startTime = new Date().getTime();
 
  // Здесь находится тестируемый код DOM
 
  setTimeout(function () {
    var endTime = new Date().getTime();
    var result = (endTime-startTime)/1000;
    // Вывод результата
  },10)
}

Здесь происходит следующее:

1. Получение времени начала теста.
2. Манипуляция с DOM в памяти браузера.
3. Определение функции, получающей время и вычисляющей результат; установка задержки.
4. Выход из функции, только теперь браузер начинает отображать результаты изменений в DOM.
5. После завершения манипуляций с DOM браузер готов обработать задержку, вызывается функция, получающая время и выводящая результат.

Другими словами, этот код позволит нам замерять ещё и время, необходимое браузеру для отображения результатов на экране.

Именно это мы и хотим знать. Если браузер чрезвычайно быстро производит манипуляции с DOM в памяти, но медленно выводит их на экран, в результате пользователь заметит именно медлительность.

Это не какие-то случайные теоретические выдумки. Я попробовал обе методики в Safari на iPhone 2.2 в тесте с генерацией 5 000 элементов списка. Первый, неверный метод занял порядка 3 секунд, в то время, как второй, верный метод потратил целых 14 секунд. Разница в 11 секунд.

(Мне интересны результаты для iPhone 3. Я намеренно не обновлял свой iPhone, поскольку ещё есть тесты, которые я бы хотел провести на операционной системе версии 2.2.)

Иначе говоря, iPhone 2.2 требуется 3 секунды для выполнения необходимых вычислений в памяти, но впоследствии ещё 11 секунд для отображения изменений на экране. Другими словами, это медленно. Первый метод этого не показывает, для точного измерения потребуется второй.

Подводя итог, напомню, что когда вы проводите замеры скорости, время окончания должно быть измерено только после того, как браузер отобразит результаты на экране.