Контролируйте и точно измеряйте, как долго изображение отображается

Для изучения времени реакции ( см. Также этот вопрос, если вам интересно) мы хотим контролировать и измерять время отображения изображений. Мы бы хотели учесть время, необходимое для перекраски на машинах разных пользователей.

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

Позже я обнаружил событие " MozAfterPaint ". Требуется изменение конфигурации для запуска на компьютерах пользователей, и соответствующий WebkitAfterPaint этого не сделал. Это означает, что я не могу использовать его на компьютерах пользователей, но я использовал его для собственного тестирования. Я вставил соответствующие фрагменты кода и результаты моих тестов ниже.
Я также вручную проверил результаты с помощью SpeedTracer в Chrome.

// from the loop pre-rendering images for faster display
var imgdiv = $('<div class="trial_images" id="trial_images_'+i+'" style="display:none"><img class="top" src="' + toppath + '"><br><img class="bottom" src="'+ botpath + '"></div>');
Session.imgs[i] = imgdiv.append(botimg);
$('#trial').append(Session.imgs);

// in Trial.showImages
$(window).one('MozAfterPaint', function () {
    Trial.FixationHidden = performance.now();
});
$('#trial_images_'+Trial.current).show(); // this would cause reflows, but I've since changed it to use the visibility property and absolutely positioned images, to minimise reflows
Trial.ImagesShown = performance.now();

Session.waitForNextStep = setTimeout(Trial.showProbe, 500); // 500ms    

// in Trial.showProbe
$(window).one('MozAfterPaint', function () {
    Trial.ImagesHidden = performance.now();
});
$('#trial_images_'+Trial.current).hide();
Trial.ProbeShown = performance.now();
// show Probe etc...

Результаты сравнения длительностей, измеренных с использованием MozAfterPaint и встроенного выполнения.

Это не делает меня слишком счастливым. Во-первых, средняя продолжительность отображения примерно на 30 мс меньше, чем хотелось бы. Во-вторых, дисперсия с использованием MozAfterPaint довольно велика (и больше, чем для встроенного выполнения), поэтому я не могу просто настроить ее, увеличив setTimeout на 30 мс. В-третьих, это на моем довольно быстром компьютере, результаты для других компьютеров могут быть хуже.

Boxplot of длительности

Соотношение длительностей, измеренных двумя методами

Результаты от SpeedTracer

Это было лучше. Время, когда изображение было видимым, обычно находилось в пределах 4 (иногда) 10 мс от предполагаемой продолжительности. Выглядело также, как будто Chrome учитывал время, необходимое для перекраски в setTimeout вызов (таким образом, между вызовами была разница в 504 мс, если изображение необходимо перекрасить). К сожалению, я не смог проанализировать и построить результаты для многих испытаний в SpeedTracer, потому что он только записывает на консоль. Я не уверен, отражает ли расхождение между SpeedTracer и MozAfterPaint различия в двух браузерах или что-то, чего не хватает в моем использовании MozAfterPaint (я вполне уверен, что правильно интерпретировал вывод SpeedTracer).

Вопросы

Я хотел бы знать

  1. Как я могу измерить время, когда оно фактически было видно на компьютере пользователя, или, по крайней мере, получить сопоставимые значения для набора различных браузеров на разных компьютерах для тестирования (Chrome, Firefox, Safari)?
  2. Могу ли я компенсировать время рендеринга и рисования, чтобы получить фактическую видимость 500 мс? Если бы мне пришлось полагаться на универсальное смещение, это было бы хуже, но все же лучше, чем показывать изображения в течение столь короткого промежутка времени, чтобы пользователи не видели их сознательно на несколько медленных компьютерах.
  3. Мы используем setTimeout, Я знаю о requestAnimationFrame но не похоже, что мы могли бы получить какие-либо выгоды от его использования:
    Предполагается, что исследование будет сосредоточено на всей продолжительности исследования, и более важно, чтобы мы получили отображение +/-500 мс, чем определенное количество кадров в секунду. Правильно ли мое понимание?

Очевидно, что Javascript не идеален для этого, но он наименее вреден для наших целей (исследование должно выполняться в режиме онлайн на собственных компьютерах пользователей, прося их установить что-то, что может отпугнуть, Java не включена в браузеры Mac OS X). больше).
На данный момент мы разрешаем только текущие версии Safari, Chrome, Firefox и, возможно, MSIE (функция обнаружения для performance.now и полноэкранного API, я еще не проверял, как работает MSIE).

2 ответа

Решение

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

Статистика

Новые результаты

  • В самой левой панели вы видите распределение, которое заставило меня усомниться в оценках времени, которые я получал.
  • Средняя панель показывает, чего я добился после кэширования селекторов, переупорядочивания некоторых вызовов, использования еще нескольких цепочек, минимизации повторных обращений с помощью visibility и абсолютное позиционирование вместо display,
  • Крайняя правая панель показывает, что я получил после использования адаптированной функции Джо Ламберта с использованием requestAnimationFrame. Я сделал это после прочтения поста блога о том, что rAF теперь имеет точность до миллисекунды. Я думал, что это только поможет мне сгладить анимацию, но, очевидно, это также поможет улучшить фактическую длительность отображения.

Результаты

На последней панели среднее значение для времени "отрисовки к краске" составляет ~500 мс, среднее значение для времени выполнения в линейном режиме рассеивается реалистично (имеет смысл, потому что я использую ту же метку времени для завершения внутреннего цикла ниже) и коррелирует с "рисовать -покрасить "сроки".

Различия в продолжительности еще немного, и я бы хотел их уменьшить, но это определенно прогресс. Мне придется протестировать его на некоторых более медленных и некоторых компьютерах с Windows, чтобы увидеть, действительно ли я доволен этим, изначально я надеялся получить все отклонения ниже 10 мс.

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

window.requestTimeout используя window.requestAnimationFrame

window.requestTimeout = function(fn, delay) {
    var start = performance.now(),
        handle = new Object();
    function loop(){
        var current = performance.now(),
            delta = current - start;

        delta >= delay ? fn.call() : handle.value = window.requestAnimationFrame(loop);
    };
    handle.value = window.requestAnimationFrame(loop);
    return handle;
};

Редактировать:

Ответ на другой мой вопрос связан с хорошей новой статьей.

Вы пытались получить начальные миллисекунды, и после того, как событие запущено, вычислите разницу? вместо setTimeout. что-то вроде:

var startDate = new Date();
var startMilliseconds = startDate.getTime();

// when the event is fired :
(...), function() {
    console.log(new Date().getTime() - startMilliseconds);
});

по возможности старайтесь избегать использования jQuery. простой JS даст вам лучшее время отклика и лучшую общую производительность

Другие вопросы по тегам