В современном мире производительность действительно имеет значение. Разработчики должны быть в состоянии точно измерить производительность своего программного обеспечения. Для тех, кто работает в Интернете, W3C имеет совершенно новый API для надежного хранения времени. Этот API является API-интерфейсом High Resolution Time . В этой статье мы рассмотрим API высокого разрешения и покажем, как его использовать.
Для измерения производительности функции веб-разработчики использовали метод JavaScript Date.now()
. Как правило, временный код выглядит примерно так:
var startTime = Date.now(); // A time consuming function foo(); var test1 = Date.now(); // Another time consuming function bar(); var test2 = Date.now(); // Print results console.debug("Test1 time: " + (test1 - startTime)); console.debug("Test2 time: " + (test2 - test1));
Метод Date.now()
извлекает текущую метку времени на основе системного времени. К сожалению, его точность варьируется в зависимости от пользовательских агентов, поэтому он не очень надежен. Чтобы смягчить эту проблему, W3C стандартизировал API времени с высоким разрешением . API описывается как « интерфейс JavaScript, который отображает текущее время с точностью до миллисекунды и не подвержен перекосу или настройке системных часов
». 23 октября 2012 года спецификация стала Предложенной рекомендацией W3C — окончательной шаг, прежде чем стать рекомендацией. 17 декабря они стали Рекомендацией W3C ( обновлено 17 декабря)
Как работает API высокого разрешения
Должен признать, это самый простой API, который я когда-либо читал, поскольку он состоит только из одного метода. API расширяет интерфейс Performance
, который также используется API-интерфейсом Navigation Timing . Если вы никогда не слышали об этом, взгляните на Navigation Timing API: Как эффективно профилировать загрузку страниц .
Единственный доступный метод — now()
, который возвращает DOMHighResTimeStamp
представляющий текущее время в миллисекундах. Отметка времени очень точная, с точностью до тысячной доли миллисекунды. Обратите внимание, что хотя Date.now()
возвращает количество миллисекунд, прошедших с 1 января 1970 года, 00:00:00 UTC, performance.now()
возвращает число миллисекунд с микросекундами в дробной части из performance.timing.navigationStart()
, начало навигации по документу, к вызову performance.now()
. Другое важное различие между Date.now()
и performance.now()
заключается в том, что последний монотонно увеличивается, поэтому разница между двумя вызовами никогда не будет отрицательной.
Возможно, вам интересно, как API с высоким разрешением изменит ваш код. Хорошая новость в том, что это ничего не изменит. Все, что вам нужно сделать, это Date.now()
с performance.now()
чтобы повысить точность ваших измерений. Принимая это во внимание, предыдущий код будет переписан, как показано ниже.
var startTime = performance.now(); // A time consuming function foo(); var test1 = performance.now(); // Another time consuming function bar(); var test2 = performance.now(); // Print more accurate results console.debug("Test1 time: " + (test1 - startTime)); console.debug("Test2 time: " + (test2 - test1));
Совместимость
В настоящее время очень немногие браузеры поддерживают API высокого разрешения. Единственными браузерами для настольных компьютеров, которые поддерживают API, являются Internet Explorer 10, Firefox 15+ без префикса и Chrome версии 20 с префиксом «webkit» ( performance.webkitNow()
). Похоже, что Chrome начнет использовать нефиксированную версию, начиная с версии 24 . На момент написания этой статьи ни один мобильный браузер не поддерживал этот API.
Поскольку поддержка невелика, первое, что вам нужно, это функция для проверки поддержки браузера, и если она имеет префикс или нет. Следующая функция вернет пустую строку, если браузер использует версию API без префикса. Если используется префиксная версия, префикс возвращается. Если API не поддерживается, возвращается значение null
.
function getPrefix() { var prefix = null; if (window.performance !== undefined) { if (window.performance.now !== undefined) prefix = ""; else { var browserPrefixes = ["webkit","moz","ms","o"]; // Test all vendor prefixes for(var i = 0; i < browserPrefixes.length; i++) { if (window.performance[browserPrefixes[i] + "Now"] != undefined) { prefix = browserPrefixes[i]; break; } } } } return prefix; }
Для браузеров, которые не поддерживают API, доступна прокладка.
Автор Shim, Tony Gentilcore, является одним из авторов API.
В своем посте, озаглавленном « Лучший таймер для JavaScript », Gentilcore написал код, который сначала ищет встроенную поддержку, и использует метод Date.getTime()
в качестве запасного Date.getTime()
. Код показан ниже.
window.performance = window.performance || {}; performance.now = (function() { return performance.now || performance.mozNow || performance.msNow || performance.oNow || performance.webkitNow || function() { return new Date().getTime(); }; })();
Собираем все вместе
Этот раздел проведет вас через простую демонстрационную страницу. Демонстрация сначала проверит поддержку браузера, а затем использует функцию doBenchmark
которая опирается на две фиктивные функции для выполнения теста с использованием метода performance.now()
. Обратите внимание, что я ввел функцию getTime()
которая не связана с API. Его единственная цель — избегать бесполезных повторений и иметь более чистый код. Исходный код демо-версии показан ниже.
<!DOCTYPE html> <html> <head> <title>High Resolution Time API Test Page</title> <script> function foo() { for(var i = 0; i < 10000000; i++); } function bar() { for(var i = 0; i < 100000000; i++); } function getPrefix() { var prefix = null; if (window.performance !== undefined) { if (window.performance.now !== undefined) prefix = ""; else { var browserPrefixes = ["webkit","moz","ms","o"]; // Test all vendor prefixes for(var i = 0; i < browserPrefixes.length; i++) { if (window.performance[browserPrefixes[i] + "Now"] != undefined) { prefix = browserPrefixes[i]; break; } } } } return prefix; } function getTime() { return (prefix === "") ? window.performance.now() : window.performance[prefix + "Now"](); } function doBenchmark() { if (prefix === null) document.getElementById("log").innerHTML = "Your browser does not support High Resolution Time API"; else { var startTime = getTime(); foo(); var test1 = getTime(); bar(); var test2 = getTime(); document.getElementById("log").innerHTML += "Test1 time: " + (test1 - startTime) + "<br />"; document.getElementById("log").innerHTML += "Test2 time: " + (test2 - test1) + "<br />"; } } var prefix = getPrefix(); window.onload = doBenchmark; </script> </head> <body> <p id="log"></p> </body> </html>
Вывод
В этой статье я показал, что такое API высокого разрешения и как его использовать. Как я уже упоминал, он пока широко не поддерживается, поэтому для точного тестирования ваших веб-приложений у вас еще есть время подождать. Однако, как вы видели, API очень прост, поскольку состоит из одного метода. Таким образом, как только улучшится поддержка браузера, переход на высокое разрешение будет быстрым и безболезненным.