Анализ сетевых характеристик с использованием JavaScript и DOM, часть 2

В части 1 этой серии мы посмотрели, как работают базовые протоколы Web и как мы можем использовать JavaScript для оценки их характеристик производительности. В этой второй части мы рассмотрим DNS, IPv6 и новую спецификацию W3C для API Навигации.

DNS Разъяснения

Каждое устройство, подключенное к Интернету, идентифицируется по цифровому адресу, известному как IP-адрес. Двумя формами IP-адресов, замеченных в открытом Интернете, являются IPv4, который представляет собой 32-битное число, часто представленное как серия из четырех десятичных чисел, разделенных точками, 80.72.139.101 например, и IPv6, который представляет собой 128-битное число, представленное как серия множественных гексадецовых чисел разделены толстой кишки, 2607:f298:1:103::c8c:a407 например. .

Дальнейшее чтение на SmashingMag:

Эти адреса хороши для понимания компьютерами; они занимают фиксированное количество байтов и могут быть легко обработаны, но они трудно для людей, чтобы помнить. Они также не очень хороши для брендинга, и часто привязаны к географическому местоположению или поставщику услуг инфраструктуры (например, провайдеру или хостинг-провайдеру).

Чтобы обойти эти недостатки, была изобретена«Система доменных имен». В своей простейшем виде, DNS создает отображение между человеком читаемым именем, как » www.smashingmagazine.com и его машина читаемый адрес ( 80.72.139.101 ). DNS может содержать гораздо больше информации, но это все, что важно для этой статьи.

Сейчас мы сосредоточимся на задержке DNS и на том, как мы можем измерить ее с помощью JavaScript из браузера. Задержка DNS важна, потому что браузеру необходимо сделать поиск DNS для каждого уникального хоста, что он должен загружать ресурсы с — даже если несколько хостеров карта на тот же IP-адрес.


Больший вид

Измерение времени поиска DNS

Простой способ измерить время поиска DNS с JavaScript будет сначала измерить задержку хоста к хосту, используя его IP-адрес, а затем измерить его снова, используя его хост-имя. Разница между ними должна дать нам время поиска DNS. Мы используем методы, разработанные в части 1 для измерения задержки.

Проблема с этим подходом заключается в том, что если браузер уже сделал поиск DNS на этом хост-имя, то этот поиск будет кэшировать, и мы действительно не получить разницу. Что нам нужно, это подстановочный знак DNS записи, и веб-сервер прослушивания на нем. Карлос Буэно сделал большой рецензии об этом на блоге YDN несколько лет назад, и построил код, который использует бумеранг.

Прежде чем мы рассмотрим код, давайте взглянем на то, как DNS поиск работы со следующей (упрощенной) диаграммы:

DNS Lookup path from Client to Authoritative Server
Слева направо: Клиент здесь браузер, DNS-сервер (как правило) isP пользователя, корневой сервер имя знает, где искать большинство доменов (или кто спрашивает, если он не знает о них), и, наконец, авторитетный сервер, который является DNS сервера веб-сайтов владелец ite.

Каждый из этих слоев имеет свой собственный кэш, и этот кэш обычно прилипает до тех пор, пока TTL авторитетного сервера (известный как «Time To Live») говорит, что он должен; но не все серверы следуют спецификации (и это полная тема для себя).

Теперь давайте посмотрим на код:

var dns_time;

function start() {
    var gen_url, img,
        t_start, t_dns, t_http,
        random = Math.floor(Math.random()*(2147483647)).toString(36);

    // 1. Create a random hostname within our domain
    gen_url = "http://*.foo.com".replace(/*/, random);

    var A_loaded = function() {
        t_dns = new Date().getTime() - t_start;

        // 3. Load another image from the same host (see step 2 below)
        img = new Image();
        img.onload = B_loaded;

        t_start = new Date().getTime();
        img.src = gen_url + "image-l.gif?t=" + (new Date().getTime()) + Math.random();
    };

    var B_loaded = function() {
        t_http = new Date().getTime() - t_start;

        img = null;

        // 4. DNS time is the time to load the image with uncached DNS
        //    minus the time to load the image with cached DNS

        dns_time = t_dns - t_http;
    };

    // 2. Load an image from the random hostname
    img = new Image();
    img.onload = A_loaded;

    t_start = new Date().getTime();
    img.src = gen_url + "image-l.gif?t=" + (new Date().getTime()) + Math.random();

}

Давайте быстро пройдем через код. То, что мы сделали здесь:

  1. Создайте случайное имя хоста, закрепленное на нашем домене подстановочных знаков. Это гарантирует, что поиск хоста не кэширован никем.
  2. Загрузите изображение из этого узла и измерьте время, необходимое для его загрузки.
  3. Загрузите другое изображение из того же узла и измерьте время загрузки.
  4. Рассчитайте разницу между двумя измеренными временами.

Первый измеренный период времени включает время поиска DNS, время рукопожатия TCP и задержку сети. Второй измеряемый раз включает задержку сети.

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

Кроме того, что, вероятно, делает его трудным для большинства людей для реализации является создание подстановочного знака DNS записи. Это не всегда возможно, если вы не контролируете свои DNS-серверы. Многие поставщики общих хостингов не позволят настроить запись DNS подстановочного знака. Единственное, что вы можете сделать в этом случае, чтобы переместить хостинг-провайдеров, или, по крайней мере DNS провайдеров.

Измерение поддержки и задержки IPv6

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

Тест IPv6 в бумеранге поможет вам определить, есть ли у пользователей поддержка IPv6 и как их задержка IPv6 сравнивается с задержкой IPv4. Он не проверяет, если их поддержка IPv6 нарушается или нет (но см. Страницу теста IPv6 от Google, если вы хотите знать это).

В тесте IPv6 есть две части:

  1. Во-первых, мы проверяем, можем ли мы подключиться к хосте, используя его адрес IPv6, и если мы можем, мы измеряем, сколько времени это занимает.
  2. Далее мы пытаемся подключиться к имени хоста, которое разрешается только с адресом IPv6.

Первый тест говорит нам, если сеть пользователя может сделать IPv6 соединений. Второй говорит нам, если их DNS-сервер может искать записи AAAA. Нам нужно запустить тест в этом порядке, потому что мы не смогли бы правильно протестировать DNS, если соединения на уровне IP сбой.

Код очень похож на тест DNS, за исключением того, что нам не нужна запись подстановочного знака DNS:

var ipv6_url = "http://[2600:1234::d155]/image-l.gif",
    host_url = "http://ipv6.foo.com/image-l.gif",
    timeout: 1200,

    ipv6_latency='NA', dnsv6_latency='NA',

    timers: {
        ipv6: { start: null, end: null },
        host: { start: null, end: null }
    };

var img,
    rnd = "?t=" + (new Date().getTime()) + Math.random(),
    timer=0, error = null;

img = new Image();

function HOST_loaded() {
    // 4. When image loads, record its time
    timers['host'].end = new Date().getTime();
    clearTimeout(timer);
    img.onload = img.onerror = null;
    img = null;

    // 5. Calculate latency
    done();
}

function error(which) {
    // 6. If any image fails to load or times out, terminate the test immediately
    timers[which].supported = false;
    clearTimeout(timer);
    img.onload = img.onerror = null;
    img = null;

    done();
}

function done() {
    if(timers['ipv6'].end !== null) {
        ipv6_latency = timers.ipv6.end - timers.ipv6.start;
    }
    if(timers['host'].end !== null) {
        dnsv6_latency = timers.host.end - timers.host.start;
    }
}

img.onload = function() {
    // 2. When image loads, record its time
    timers['ipv6'].end = new Date().getTime();
    clearTimeout(timer);

    // 3. Then load image with hostname that only resolves to ipv6 address
    img = new Image();
    img.onload = HOST_loaded;
    img.onerror = function() { error('host') };

    timer = setTimeout(function() { error('host') }, timeout);

    timers['host].start = new Date().getTime();
    img.src = host_url + rnd;
};

img.onerror = function() { error('ipv6') };
timer = setTimeout(function() { error('ipv6') }, timeout);
this.timers['ipv6'].start = new Date().getTime();
// 1. Load image with ipv6 address
img.src = ipv6_url + rnd;

Да, этот код можно рефакторовать, чтобы сделать его меньше, но это затруднит объяснение. Это то, что мы делаем:

  1. Сначала мы загружаем изображение с узла, используя его адрес IPv6. Это проверяет, чтобы увидеть, что мы можем сделать сетевое подключение к адресу IPv6. Если ваша сеть, браузер или ОС не поддерживают IPv6, это сведет на нет, и событие onerror загорится.
  2. Если изображение загружается, мы знаем, что соединения IPv6 поддерживаются. Мы записываем время, которое мы будем использовать для измерения задержки позже.
  3. Затем мы пытаемся загрузить изображение с помощью хоста, который разрешается только с адресом IPv6. Важно, чтобы это хостатовое имя не решило с адресом IPv4 или этот тест может пройти, даже если dNS-сервер не может обрабатывать IPv6.
  4. Если это удастся, мы знаем, что наш DNS-сервер может искать и возвращать записи AAAA (эквивалент IPv6 A). Мы записываем время.
  5. А потом идти вперед и рассчитать задержку. Мы можем сравнить это с нашей задержкой IPv4 и задержкой DNS. Это также было бы подходящим местом для вызова любой функции обратного вызова, чтобы сказать, что тест завершен.
  6. Если какая-либо из загрузок изображения произвела событие onerror или если они приурочены, мы немедленно прекращаем тест. В этом случае любые тесты, которые не были запущены, имеют соответствующую переменную ipv6_latency dnsv6_latency (или) набор «NA», не указывающие на поддержку.

Существуют и другие способы проверки поддержки IPv6 с помощью серверной стороны, например, чтобы ваш сервер установил файл cookie, в котором было указано, был ли он загружен через IPv4 или IPv6. Это работает хорошо, только если ваша страница тестирования и ваша страница изображения находятся на том же домене.

API навигацииTiming

NavigationTiming API — это интерфейс, предоставляемый многими современными браузерами, который дает разработчикам JavaScript подробную информацию о времени, проведенном браузером в различных состояниях загрузки страницы. Спецификация все еще находится в состоянии проекта, но на дату этой статьи, Internet Explorer, Chrome и Firefox поддерживают его. Safari и Opera в настоящее время не поддерживают API.

Разработчики JavaScript получают доступ к объекту NavigationTiming через window.performance.timing . Попробуйте это сейчас. Если вы используете Chrome, IE 9 «или Firefox 8» , откройте веб-консоль и проинспектировать содержимое window.performance.timing .

На приведенной ниже диаграмме объясняется порядок событий, время которых отображается в объекте. Давайте посмотрим на некоторые из них:

Navigation Timing Overview diagram from the W3C
Большее представление Источник изображения

Теперь элементы, которые мы были заинтересованы в измерении являются:

  1. Время загрузки страницы Мы получаем полное время загрузки страницы, принимая разницу между loadEventEnd и navigationStart . Последний сообщает нам, когда пользователь инициировал загрузку страницы, либо нажав на ссылку, либо введя ее в URL-бар своего браузера. Последний говорит нам, когда onload мероприятие закончилось. Если мы не заинтересованы в времени выполнения onload события, мы могли бы использовать loadEventStart вместо этого.
  2. Задержка сети/приложений Задержка сети — это время от браузера, искрометирующего загрузку, до момента, когда появился первый байт. Теперь, часть этой задержки может быть отнесена к приложению делать что-то перед отправкой байтов, но нет никакого способа узнать, что со стороны клиента. Мы используем разницу между requestStart и responseStart .
  3. Время подключения TCP Время подключения TCP является разница между connectStart и connectEnd , однако, если соединение над SSL, то это включает в себя время для переговоров SSL рукопожатие. Вы должны принять это во внимание, и использовать secureConnectionStart вместо того, connectEnd если она существует, и если вы заботитесь о разнице.
  4. Задержка DNS Задержка DNS – это разница между domainLookupStart и domainLookupEnd .

Важно: Мы используем комбинацию раз, window.performance.timing чтобы определить каждый из них.

Хотя это выглядит хорошо по большей части, и действительно говорит вам, что ваши пользователи испытывают, Есть несколько оговорок, чтобы быть в курсе. Если DNS уже кэширован, то задержка DNS будет 0 . Аналогичным образом, если браузер использует постоянное соединение TCP, то время подключения TCP будет 0 . Если документ зачитывается из кэша, то задержка сети будет 0 . Имейте в виду эти моменты и используйте их, чтобы определить, какая часть пользователей эффективно использует доступные кэши приложений.

Интерфейс Навигация Тайминг предоставляет нам гораздо больше таймер, но некоторые из них ограничены той же политики происхождения браузера. К ним относятся сведения о перенаправлениях и разгрузке предыдущей страницы. Другие таймеры, связанные с DOM, уже имеют эквивалентные события JavaScript, а именно readystatechange события DOMComplete и load события.

Информационный ими идолдля сети

Другой интересный аиП, связанный с сетью, — API сетевой информации. Хотя это и не связано с производительностью, это помогает делать догадки в ожидаемой производительности сети. Этот API в настоящее время поддерживается только устройствами Android и подвергается воздействию через navigator.connection.type объект. В частности, он говорит вам, является ли устройство в настоящее время с помощью Ethernet, Wi-Fi, 2G или 3G.

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

Сводка

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

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

Все методы, представленные здесь были разработаны при написании Boomerang, хотя не все из них сделали его в код еще.

Ссылки

Следующие ссылки помогли в написании этой статьи и могут быть переданы для получения дополнительной информации по конкретным темам:

(Кредиты изображения на первой странице: Власта Джурисек)

(il) (ea)

Источник: smashingmagazine.com

Великолепный Журнал

Великолепный, сокрушительный, разящий (см. перевод smashing) независимый журнал о веб-разработке. Основан в 2006 году в Германии. Имеет няшный дизайн и кучу крутых авторов, которых читают 2 млн человек в месяц.

Добавить комментарий

%d такие блоггеры, как: