Анализ производительности вашего веб-приложения в Internet Explorer 11 и в других браузерах в реальных условиях

Совместно с Google, Mozilla и другими лидерами сообщества рабочая группа консорциума W3C по стандарту Web Performance довела до уровня стандартов интерфейсы Navigation Timing, Resource Timing, User Timing и Performance Timeline, чтобы помочь вам анализировать производительность навигации, загрузки ресурсов и выполнения скриптов в вашем веб-приложении в реальных условиях. Вы можете использовать эти интерфейсы для получения и анализа данных о том, как ваши клиенты взаимодействуют с вашим веб-приложением в реальных условиях, не полагаясь на результаты искусственного тестирования, при котором проверяется производительность приложения в искусственной среде. С помощью этих данных о времени вы можете определять возможности улучшения производительности ваших веб-приложений в реальных условиях. Все эти интерфейсы поддерживаются в Internet Explorer 11. Ознакомьтесь с тестовой демонстрацией Performance Timing, чтобы увидеть эти интерфейсы в действии.

Тестовая демонстрация Performance Timing позволяет опробовать API-интерфейсы Timing.
Тестовая демонстрация Performance Timing позволяет опробовать API-интерфейсы Timing.

Performance Timeline

Спецификация Performance Timeline была опубликована как рекомендация (Recommendation) консорциума W3C и полностью поддерживается браузерами Internet Explorer 11 и Chrome 30. С помощью этого интерфейса вы можете получить исчерпывающую информацию о времени, потраченном на навигацию, загрузку ресурсов и выполнение скриптов в вашем приложении. В этой спецификации определены как минимальные атрибуты, которые должны быть реализованы во всех метриках производительности, так и интерфейсы, которые могут использоваться разработчиками для получения метрики производительности любого типа.

Все метрики производительности должны поддерживать следующие четыре атрибута:

  • name. В этом атрибуте хранится уникальный идентификатор метрики производительности. Например, для ресурса это будет его разрешенный URL-адрес.
  • entryType. В этом атрибуте хранится тип метрики производительности. Например, метрика для ресурса будет храниться как "resource".
  • startTime. В этом атрибуте хранится первая зарегистрированная метка времени для данной метрики производительности.
  • duration. В этом атрибуте хранится полная длительность события, зарегистрированного данной метрикой.

Все данные о времени регистрируются в формате высокоточного времени с использованием типа DOMHighResTimeStamps, определенного в спецификации High Resolution Time. В отличие от DOMTimeStamps, где значения времени измеряются в миллисекундах с 1 января 1970 г. в формате UTC, высокоточное значение времени измеряется по крайней мере с микросекундным разрешением и отсчитывается от начала просмотра документа. Например, если я проверяю текущее время с помощью performance.now() (высокоточное время, аналогичное Date.now()), я получу следующую интерпретацию текущего времени:

> performance.now();

4038.2319370044793

 

> Date.now()

1386797626201

Это значение времени обладает также преимуществом независимости от расфазировки или настройки синхронизирующих импульсов. Чтобы разобраться в использовании высокоточного времени, ознакомьтесь с тестовой демонстрацией What Time Is It.

Для получения списка метрик производительности, зарегистрированных во время вызова, можно использовать следующие интерфейсы. Используя атрибуты startTime и duration, а также любые другие атрибуты, предоставляемые метрикой, вы можете получить исчерпывающую картину производительности вашей страницы при ее просмотре вашими клиентами.

PerformanceEntryList getEntries();

PerformanceEntryList getEntriesByType(DOMString entryType);

PerformanceEntryList getEntriesByName(DOMString name, optional DOMString entryType);

Метод getEntriesвозвращает список всех метрик производительности на странице, а остальные методы возвращают особые элементы в зависимости от имени или типа. Мы предполагаем, что большинство разработчиков будут просто использовать метод JSON stringify для всего списка метрик и отправлять результаты на свой сервер (а не на клиент) для анализа.

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

Navigation Timing

Интерфейсы Navigation Timing предоставляют точные измерения времени для каждого этапа перехода в ваше веб-приложение. Спецификация Navigation Timing L1 была опубликована как рекомендация (Recommendation) консорциума W3C и полностью поддерживается в браузерах начиная с Internet Explorer 9, Chrome 28 и Firefox 23. Спецификация Navigation Timing L2 является первым общедоступным рабочим черновиком (First Public Working Draft) и поддерживается Internet Explorer 11.

C помощью Navigation Timing разработчики могут узнать не только точное время загрузки страниц, включая время получения страницы с сервера, но и то, на что было потрачено это время на каждом этапе работы с сетью и обработки DOM: на выгрузку, перенаправление, кэш приложения, DNS, TCP, запрос, ответ, обработку DOM и событие загрузки. В следующем скрипте для получения такой подробной информации используется Navigation Timing L2. Тип записи для этой метрики — "navigation", а имя — "document". Ознакомьтесь с демонстрацией Navigation Timing на сайте тестирования Internet Explorer.

<!DOCTYPE html>

<html>

<head></head>

<body>

<script>

 function sendNavigationTiming() {

   var nt = performance.getEntriesByType('navigation')[0];

   var navigation = ' Start Time: ' + nt.startTime + 'ms';

   navigation += ' Duration: ' + nt.duration + 'ms';

   navigation += ' Unload: ' + (nt.unloadEventEnd - nt.unloadEventStart) + 'ms';

   navigation += ' Redirect: ' + (nt.redirectEnd - nt.redirectStart) + 'ms';

   navigation += ' App Cache: ' + (nt. domainLookupStart - nt.fetchStart) + 'ms';

   navigation += ' DNS: ' + (nt.domainLookupEnd - nt.domainLookupStart) + 'ms';

   navigation += ' TCP: ' + (nt.connectEnd - nt.connectStart) + 'ms';

   navigation += ' Request: ' + (nt.responseStart - nt.requestStart) + 'ms';

   navigation += ' Response: ' + (nt.responseEnd - nt.responseStart) + 'ms';

   navigation += ' Processing: ' + (nt.domComplete - nt.domLoading) + 'ms';

   navigation += ' Load Event: ' + (nt.loadEventEnd - nt.loadEventStart) + 'ms';

   sendAnalytics(navigation);

 }

</script>

</body>

</html>

Тщательно изучив время, потраченное на каждом этапе использования сети, вы можете лучше диагностировать и исправлять неполадки, связанные с производительностью. Например, вы можете отказаться от использования перенаправления, если оно занимает много времени, можете использовать службу кэша, если много времени тратится на DNS, использовать сеть доставки контента, находящуюся ближе к вашим пользователям, если много времени уходит на выполнение запроса, или сжать контент с помощью GZip, если много времени тратится на ответ. Посмотрите это видео, в котором вы найдете советы и рекомендации по улучшению производительности использования сети.

Основное отличие между этими двумя версиями спецификации Navigation Timing заключается в способе доступа к данным о времени и способе измерения времени. В интерфейсе L1 эти атрибуты определяются в объекте performance.timing в миллисекундах с 1 января 1970 г. Интерфейс L2 позволяет извлекать те же атрибуты с помощью методов Performance Timeline и более удобно размещать их в представлении временной шкалы, причем они записываются с помощью высокоточных таймеров.

До появления Navigation Timing разработчики обычно пытались измерить время загрузки страницы посредством написания кода JavaScript в заголовке документа, как в следующем примере кода. Ознакомьтесь с демонстрацией этого способа на сайте тестирования Internet Explorer.

<!DOCTYPE html>

<html>

<head>

<script>

    var start = Date.now();

 

    function sendPageLoad() {

        var now = Date.now();

        var latency = now - start;

        sendAnalytics('Page Load Time: ' + latency);

    }

 

</script>

</head>

<body onload='sendPageLoad()'>

</body>

</html>

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

Resource Timing

Интерфейс Resource Timing предоставляет точную информацию о времени загрузки ресурсов на странице. Аналогично Navigation Timing интерфейс Resource Timing предоставляет подробные данные о времени выполнения таких этапов, как перенаправление, DNS, TCP, запрос и ответ, для загружаемых ресурсов. Спецификация Resource Timing была опубликована как кандидат к рекомендации (Candidate Recommendation) консорциума W3C и поддерживается начиная с версий Internet Explorer 10 и Chrome 30.

В следующем примере кода используется метод getEntriesByType для получения всех ресурсов, инициированных элементом <img>. Тип записи для ресурсов — "resource", а имя — разрешенный URL-адрес ресурса. Ознакомьтесь с демонстрацией Resource Timing на сайте тестирования Internet Explorer.

<!DOCTYPE html>

<html>

  <head>

  </head>

  <body onload='sendResourceTiming()'>

    <img src='http://some-server/image1.png'>

    <img src='http://some-server/image2.png'>

 

    <script>

        function sendResourceTiming()

        {

            var resourceList = window.performance.getEntriesByType('resource');

            for (i = 0; i < resourceList.length; i++)

            {

                if (resourceList[i].initiatorType == 'img')

                {

                    sendAnalytics('Image Fetch Time: ' + resourceList[i].duration);

                }

            }

        }

    </script>

  </body>

</html>

В целях безопасности для ресурсов из других источников отображается только время начала загрузки и ее длительность; подробные атрибуты времени имеют нулевое значение. Это помогает избежать проблем, связанных со статистическим отслеживанием ("фингерпринтингом"), когда некто может попытаться определить ваше участие в организации путем проверки того, находится ли ресурс в вашем кэше, посредством изучения подробных данных о времени использования сети. Сервер из другого источника может отправить HTTP-заголовок timing-allow-origin, если "хочет" обмениваться с вами данными о времени.

User Timing

Интерфейс User Timing предоставляет подробную информацию о времени выполнения скриптов в вашем приложении, дополняя интерфейсы Navigation Timing и Resource Timing, предоставляющие подробную информацию о времени использования сети. User Timing позволяет отображать данные о времени выполнения скриптов в том же представлении временной шкалы, что и данные о времени использования сети, для всестороннего анализа производительности вашего приложения. Спецификация User Timing была опубликована как кандидат к рекомендации (Candidate Recommendation) консорциума W3C и поддерживается начиная с версий Internet Explorer 10 и Chrome 30.

Интерфейс User Timing определяет две метрики, используемые для измерения времени выполнения скриптов: метки (mark) и измерения (measure). Метка представляет собой высокоточную метку времени в заданный момент времени в процессе выполнения скрипта. Измерение представляет собой разность между двумя метками.

Для создания меток и измерений могут использоваться следующие методы:

void mark(DOMString markName);

void measure(DOMString measureName, optional DOMString startMark, optional DOMString endMark);

После добавления меток и измерений в ваш скрипт вы можете извлекать данные о времени с помощью методов getEntry, getEntryByType или getEntryByName. Тип записи метки — "mark", а тип записи измерения — "measure".

В следующем примере кода методы меток и измерений используются для определения времени, потраченного на выполнение методов doTask1() и doTask2(). Ознакомьтесь с демонстрацией User Timing на сайте тестирования Internet Explorer.

<!DOCTYPE html>

<html>

  <head>

  </head>

  <body onload='doWork()'>

    <script>

        function doWork()

        {

            performance.mark('markStartTask1');

            doTask1();

            performance.mark('markEndTask1');

           

            performance.mark('markStartTask2');

            doTask2();

            performance.mark('markEndTask2');

 

            performance.measure('measureTask1', 'markStartTask1', 'markEndTask1');

            performance.measure('measureTask2', 'markStartTask2', 'markEndTask2');

 

            sendUserTiming(performance.getEntries());

        }

    </script>

  </body>

</html>

Мы хотим поблагодарить всех участников рабочей группы консорциума W3C по стандарту Web Performance за помощь в проектировании этих интерфейсов и поставщиков браузеров за работу над реализацией этих интерфейсов для обеспечения совместимости. С помощью этих интерфейсов веб-разработчики могут по-настоящему начать измерять различные показатели и анализировать их, чтобы понять, что можно сделать для повышения производительности приложений.

Рекомендуем вам опробовать интерфейсы измерения производительности для ваших веб-приложений в Internet Explorer 11 и с нетерпением ждем ваших отзывов на сайте Connect.

Спасибо за внимание!

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