Получаем данные в Javascript с помощью XMLHttpRequest

Я очень часто вижу, что люди используют $http в Angular или jQuery или другие библиотеки и даже не знают, что выполняется внутри и как в чистом javascript работать с http запросами.

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

Именно на этой технологии работают все современные Single Page приложения.

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

Для того, чтобы обращатся на сервер за данными, давайте создадим API с тестовыми данными с помощью сервиса mocky.io.

Вот у меня есть JSON данных

[
  {
    "userId": 1,
    "id": 1,
    "title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit",
    "body": "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto"
  },
  {
    "userId": 1,
    "id": 2,
    "title": "qui est esse",
    "body": "est rerum tempore vitae\nsequi sint nihil reprehenderit dolor beatae ea dolores neque\nfugiat blanditiis voluptate porro vel nihil molestiae ut reiciendis\nqui aperiam non debitis possimus qui neque nisi nulla"
  },
  {
    "userId": 1,
    "id": 3,
    "title": "ea molestias quasi exercitationem repellat qui ipsa sit aut",
    "body": "et iusto sed quo iure\nvoluptatem occaecati omnis eligendi aut ad\nvoluptatem doloribus vel accusantium quis pariatur\nmolestiae porro eius odio et labore et velit aut"
  }
]

Вставляем его в body запроса и в advance mode выбираем

 Access-Control-Allow-Origin:*

Для того, чтобы любой домен мог обращатся к этому API.

Нажимаем Generate response и получаем ссылку на наш API.

Теперь давайте писать javascript.

Для начала нам нужно создать новый екземпляр XMLHttpRequest.

var xhr = new XMLHttpRequest()

Теперь сконфигурировать какой url мы хотим получить

var xhr = new XMLHttpRequest()
xhr.open(
  'GET',
  'http://www.mocky.io/v2/5944e07213000038025b6f30',
  true
)

Для этого на xhr мы вызываем метод open передавая туда тип запроса, url, и асинхронный ли запрос. Конечно мы хотим асинхронный. Никогда не используйте синхронные запросы, так как это блокирует продолжение скрипта. В 99 случаях из 100 этого делать не нужно.

Не стоит думать, что xhr.open выполняет запрос. Хотя из названия похоже. Он его только конфигурирует. Для отправки запроса используется xhr.send

var xhr = new XMLHttpRequest()
xhr.open(
  'GET',
  'http://www.mocky.io/v2/5944e07213000038025b6f30',
  true
)
xhr.send()

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

var xhr = new XMLHttpRequest()
xhr.open(
  'GET',
  'http://www.mocky.io/v2/5944e07213000038025b6f30',
  true
)
xhr.send()
xhr.onreadystatechange = function() {
  if (xhr.readyState != 4) {
    return
  }
  console.log('end')
}

Внутри метода мы должны проверять readyState на 4, чтобы понять, когда запрос закончится. Пока readyState ниже четверки, то запрос не закончен. Там происходит начало запроса, получение заголовкой, загрузка body и только потом запрос завершен.

Теперь давайте добавим проверку на error и вывод результатов в консоль

var xhr = new XMLHttpRequest()
xhr.open(
  'GET',
  'http://www.mocky.io/v2/5944e07213000038025b6f30',
  true
)
xhr.send()
xhr.onreadystatechange = function() {
  if (xhr.readyState != 4) {
    return
  }
  if (xhr.status === 200) {
    console.log('result', xhr.responseText)
  } else {
    console.log('err', xhr.responseText)
  }
}

Как мы видим, результат выводится в виде строки, поэтому нам нужно еще и парсить его в JSON

console. log('result', JSON.parse(xhr.responseText))

Какие же основные минусы XMLHttpRequest и почему все используют ajax в jQuery для получения данных или отдельные библиотеки для этого например superagent или axios.

Первым минус — это конечно количество кода. В любой из вспомогательных библиотек метод для работы с http запросами намного лаконичнее.

Второй — это отсутствие промисов при работе с XMLHttpRequest. Мы не можем написать .then, передать туда коллбек и выполнить что мы хотим когда запрос завершится. Поэтому с этим кодом неудобно работать.

Третий — это кроссбраузерность. Даже в IE 10-11 XMLHttpRequest работает не так, как в других браузерах.

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

Если у вас возникли какие-то вопросы или комментарии, пишите их прямо под этим видео.

15. XMLHttpRequest — высокопроизводительная сеть браузера [книга]

Глава 15. XMLHttpRequest

XMLHttpRequest (XHR) — это API уровня браузера, который позволяет клиенту создавать сценарии передачи данных через JavaScript.

Впервые XHR дебютировал в Internet Explorer 5, стал одной из ключевых технологий, лежащих в основе революции асинхронного JavaScript и XML (AJAX), и теперь является фундаментальным строительным блоком почти каждого современного веб-приложения.

XMLHTTP изменил все. Это поставило «D» в DHTML. Это позволило нам асинхронно получать данные с сервера и сохранять состояние документа на клиенте… Желание команды Outlook Web Access (OWA) создать многофункциональное приложение, подобное Win32, в браузере подтолкнуло технологию к IE, которая позволила AJAX стать реальностью.

— Джим Ван Итон Outlook Web Access: катализатор веб-развития

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

Однако сила XHR заключается не только в том, что он обеспечивает асинхронную связь внутри браузера, но и в том, что делает его простым. XHR — это прикладной API, предоставляемый браузером, то есть браузер автоматически берет на себя все низкоуровневое управление соединениями, согласование протоколов, форматирование HTTP-запросов и многое другое:

  • Браузер управляет установлением соединения, объединением в пул и завершением.
  • Браузер определяет наилучший транспорт HTTP(S) (HTTP/1.0, 1.1, 2).
  • Браузер обрабатывает кэширование HTTP, перенаправления и согласование типа контента.
  • Браузер применяет ограничения безопасности, аутентификации и конфиденциальности.
  • И еще…

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

В результате почти каждый вариант использования сети (скриптовые загрузки, выгрузки, потоковая передача и даже уведомления в реальном времени) может быть построен на основе XHR. Конечно, это не означает, что XHR является наиболее эффективным транспортом в каждом случае — на самом деле, как мы увидим, это далеко не так, — но, тем не менее, он часто используется в качестве резервного транспорта для старых клиентов, которые могут не иметь доступа. к более новым сетевым API браузера. Имея это в виду, давайте подробнее рассмотрим новейшие возможности XHR, варианты его использования, а также преимущества и недостатки производительности.

Примечание

Исчерпывающий анализ полного API XHR и его возможностей выходит за рамки нашего обсуждения — мы сосредоточены на производительности! Обратитесь к официальному стандарту W3C для обзора API XMLHttpRequest.

Краткая история XHR

Несмотря на свое название, XHR никогда не предназначался для конкретной привязки к XML. Префикс XML — это пережиток решения поставлять первую версию того, что стало известно как XHR, как часть библиотеки MSXML в Internet Explorer 5:9.0005

Это были старые добрые времена, когда критические функции были втиснуты всего за несколько дней до выпуска… Я понял, что библиотека MSXML поставляется с IE, и у меня есть хорошие контакты в команде XML, которые, вероятно, помогут мне — я связались с Жаном Паоли, который в то время руководил этой командой, и мы довольно быстро заключили сделку о поставке этой штуки как части библиотеки MSXML. Это и есть реальное объяснение того, откуда взялось название XMLHTTP — в основном это касается HTTP и не имеет какой-либо конкретной связи с XML, за исключением того, что это было самым простым оправданием для его отправки, поэтому мне нужно было втиснуть XML в имя.

— Алекс Хопманн История XMLHTTP

Mozilla смоделировала собственную реализацию XHR в сравнении с реализацией Microsoft и представила ее через интерфейс XMLHttpRequest. Затем последовали Safari, Opera и другие браузеры, а XHR стал стандартом де-факто во всех основных браузерах — отсюда и название, и почему он прижился. Фактически, официальная спецификация W3C Working Draft для XHR была опубликована только в 2006 году, намного позже того, как XHR стал широко использоваться!

Однако, несмотря на свою популярность и ключевую роль в революции AJAX, ранние версии XHR предоставляли ограниченные возможности: передача только текстовых данных, ограниченная поддержка обработки загрузок и невозможность обработки междоменных запросов. Для устранения этих недостатков в 2008 г. был опубликован проект «XMLHttpRequest Level 2», в котором добавлен ряд новых функций:

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

В 2011 году спецификация «XMLHttpRequest Level 2» была объединена с исходным рабочим проектом XMLHttpRequest. Следовательно, хотя вы часто будете находить ссылки на версию XHR или уровень 1 и 2, эти различия больше не актуальны; сегодня существует только одна унифицированная спецификация XHR. На самом деле все новые функции и возможности XHR2 предлагаются через один и тот же XMLHttpRequest API: тот же интерфейс, больше возможностей.

Примечание

Новые функции XHR2 теперь поддерживаются всеми современными браузерами; см. caniuse.com/xhr2. Следовательно, всякий раз, когда мы ссылаемся на XHR, мы неявно ссылаемся на стандарт XHR2.

Cross-Origin Resource Sharing (CORS)

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

Интерфейс XHR обеспечивает строгую семантику HTTP для каждого запроса: приложение предоставляет данные и URL-адрес, а браузер форматирует запрос и обрабатывает полный жизненный цикл каждого соединения. Точно так же, хотя API XHR позволяет приложению добавлять собственные заголовки HTTP (с помощью метода setRequestHeader() ), существует ряд защищенных заголовков, которые недоступны для кода приложения:

  • Accept-Charset, Accept-Encoding, Access-Control-*
  • Хост, Обновление, Соединение, Реферер, Происхождение
  • Cookie, Sec-*, Proxy-* и с десяток других…

Браузер откажется переопределять любой из небезопасных заголовков, что гарантирует, что приложение не сможет олицетворять поддельный пользовательский агент, пользователя или источник, откуда выполняется запрос. На самом деле защита заголовка источника особенно важна, так как это ключевой элемент «политики одного и того же источника», применяемой ко всем запросам XHR.

Примечание

«Происхождение» определяется как тройка из протокола приложения, доменного имени и номера порта, например (http, example. com, 80) и (https, example.com, 443) считаются разными происхождение. Дополнительные сведения см. в разделе Концепция веб-происхождения.

Мотивация политики единого источника проста: браузер хранит пользовательские данные, такие как токены аутентификации, файлы cookie и другие личные метаданные, которые не могут быть переданы между разными приложениями — например, без изолированной программной среды одного источника произвольный сценарий на example.com может получать доступ и управлять данными пользователей на ThirdParty.com !

Чтобы решить эту конкретную проблему, ранние версии XHR были ограничены только запросами одного и того же источника, где запрашиваемый источник должен был совпадать с источником запрошенного ресурса: XHR инициировался с example.com может запрашивать другой ресурс только из того же источника example.com . В качестве альтернативы, если то же предварительное условие источника не выполнено, браузер просто откажется инициировать запрос XHR и выдаст ошибку.

Однако, несмотря на необходимость, политика того же источника также накладывает серьезные ограничения на полезность XHR: что, если сервер захочет предложить ресурс скрипту, работающему в другом источнике? Вот тут-то и появляется «обмен ресурсами между источниками» (CORS)! CORS предоставляет безопасный механизм согласия для запросов на стороне клиента из разных источников:

Запросы CORS используют один и тот же XHR API, с той лишь разницей, что URL-адрес запрошенного ресурса связан с источником, отличным от того, где выполняется сценарий: в предыдущем примере сценарий выполняется с (http, пример .com, 80) , а второй запрос XHR обращается к resource.js из (http, ThirdParty.com, 80) .

Механизм автоматической аутентификации для запроса CORS обрабатывается на более низком уровне: когда запрос сделан, браузер автоматически добавляет защищенный Origin HTTP-заголовок, который объявляет источник, из которого был сделан запрос. В свою очередь, удаленный сервер затем может проверить заголовок Origin и решить, должен ли он разрешить запрос, возвращая заголовок Access-Control-Allow-Origin в своем ответе:

В предыдущем примере третья сторона .com решил выбрать совместное использование ресурсов между источниками с example.com , вернув соответствующий заголовок управления доступом в своем ответе. В качестве альтернативы, если он хочет запретить доступ, он может просто опустить Access-Control-Allow-Origin , и браузер клиента автоматически отклонит отправленный запрос.

Примечание

Если сторонний сервер не поддерживает CORS, запрос клиента завершится ошибкой, так как клиент всегда проверяет наличие заголовка согласия. В качестве особого случая CORS также позволяет серверу возвращать подстановочный знак ( Access-Control-Allow-Origin: * ), чтобы указать, что он разрешает доступ из любого источника. Однако подумайте дважды, прежде чем включать эту политику!

На этом мы закончили, верно? Оказывается, не совсем так, поскольку CORS принимает ряд дополнительных мер безопасности, чтобы убедиться, что сервер поддерживает CORS:

  • Запросы CORS пропускают учетные данные пользователя, такие как файлы cookie и аутентификация HTTP.
  • Клиент ограничен выдачей «простых запросов между источниками», что ограничивает как разрешенные методы (GET, POST, HEAD), так и доступ к заголовкам HTTP, которые могут быть отправлены и прочитаны XHR.

Чтобы включить файлы cookie и HTTP-аутентификацию, клиент должен установить дополнительное свойство ( withCredentials ) в объекте XHR при выполнении запроса, и сервер также должен ответить соответствующим заголовком ( Access-Control-Allow-Credentials ), чтобы указать, что он сознательно разрешает приложению включать личные данные пользователя. Точно так же, если клиенту необходимо написать или прочитать пользовательские заголовки HTTP или он хочет использовать «непростой метод» для запроса, он должен сначала запросить разрешение у стороннего сервера, выполнив предварительный запрос:

официальная спецификация W3C CORS определяет, когда и где должен использоваться предварительный запрос: «простые» запросы могут его пропустить, но существует множество условий, которые вызывают его и добавляют как минимум полную задержку в сети для проверки разрешений. Хорошей новостью является то, что после того, как сделан предварительный запрос, он может быть кэширован клиентом, чтобы избежать одинаковой проверки для каждого запроса.

Примечание

CORS поддерживается всеми современными браузерами; см. caniuse.com/cors. Для более подробного ознакомления с различными политиками и реализацией CORS обратитесь к официальному стандарту W3C.

Загрузка данных с помощью XHR

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

ArrayBuffer
Буфер двоичных данных фиксированной длины
Капля
Двоичный большой объект неизменяемых данных
Документ
Разобранный документ HTML или XML
JSON
Объект JavaScript, представляющий простую структуру данных
Текст
Простая текстовая строка

Либо браузер может полагаться на согласование типа контента HTTP, чтобы сделать вывод о соответствующем типе данных (например, декодировать application/json ответ в объект JSON), или приложение может явно переопределить тип данных при инициировании запроса XHR:

Обратите внимание, что мы передаем ресурс изображения в его собственном формате, не полагаясь на кодировку base64, и добавляем элемент изображения на страницу, не полагаясь на URI данных. При обработке полученных двоичных данных в JavaScript не возникает дополнительных затрат на передачу по сети или кодирование! XHR API позволяет нам создавать эффективные динамические приложения, независимо от типа данных, прямо из JavaScript.

Примечание

Интерфейс больших двоичных объектов является частью файлового API HTML5 и действует как непрозрачная ссылка для произвольного фрагмента данных (двоичных или текстовых). Сама по себе ссылка на большой двоичный объект имеет ограниченную функциональность: вы можете запросить ее размер, тип MIME и разбить ее на более мелкие большие двоичные объекты. Однако его реальная роль заключается в том, чтобы служить эффективным механизмом обмена между различными API-интерфейсами JavaScript.

Загрузка данных с помощью XHR

Загрузка данных с помощью XHR так же проста и эффективна для всех типов данных. На самом деле код практически такой же, с той лишь разницей, что мы также передаем объект данных при вызове 9. 0012 send() по запросу XHR. Остальное обрабатывается браузером:

Метод XHR send() принимает один из DOMString , Document , FormData , Blob , File , автоматически выполняет объекты Buffer 8 или 908 . соответствующую кодировку, устанавливает соответствующий тип содержимого HTTP и отправляет запрос. Нужно отправить двоичный BLOB-объект или загрузить файл, предоставленный пользователем? Просто: возьмите ссылку на объект и передайте ее в XHR. На самом деле, немного поработав, мы можем разбить большой файл на более мелкие фрагменты:

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

Примечание

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

Мониторинг хода загрузки и выгрузки

Сетевое подключение может быть прерывистым, а задержка и пропускная способность сильно варьируются. Итак, как мы узнаем, был ли XHR-запрос успешным, истекшим по тайм-ауту или неудачным? Объект XHR предоставляет удобный API для прослушивания событий выполнения (таблица 15-1), которые указывают текущий статус запроса.

Таблица 15-1. События прогресса XHR

Тип события Description Times fired

loadstart

Transfer has begun

once

progress

Transfer is in progress

zero or more

ошибка

Ошибка передачи

ноль или один раз0005

Transfer is terminated

zero or once

load

Transfer is successful

zero or once

loadend

Transfer has finished

один раз

Каждая передача XHR начинается с события loadstart и заканчивается событием loadend , а между ними запускается одно или несколько дополнительных событий, указывающих на состояние передачи. Следовательно, для отслеживания прогресса приложение может зарегистрировать набор прослушивателей событий JavaScript в объекте XHR:

Событие load или error сработает один раз, чтобы указать окончательный статус передачи XHR, тогда как событие progress может срабатывать любое количество раз и предоставляет удобный API для отслеживания статуса передачи: мы можем сравнить загружен атрибут против всего для оценки объема переданных данных.

Примечание

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

Кроме того, запросы XHR не имеют тайм-аута по умолчанию, что означает, что запрос может «выполняться» бесконечно. Рекомендуется всегда устанавливать разумный тайм-аут для вашего приложения и обрабатывать ошибку!

Потоковая передача данных с помощью XHR

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

  • Метод send ожидает полную полезную нагрузку в случае загрузки.
  • Атрибуты response , responseText и responseXML не предназначены для потоковой передачи.

Потоковая передача никогда не была официальным вариантом использования в рамках официальной спецификации XHR. В результате, за исключением ручного разделения загрузки на более мелкие отдельные XHR, не существует API для потоковой передачи данных с клиента на сервер. Точно так же, хотя спецификация XHR2 предоставляет некоторую возможность считывания частичного ответа с сервера, реализация неэффективна и очень ограничена. Это плохие новости.

Хорошая новость в том, что на горизонте есть надежда! Отсутствие поддержки потоковой передачи в качестве первоклассного варианта использования XHR является общепризнанным ограничением, и в настоящее время ведется работа по решению этой проблемы:

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

— API потоков W3C

Сочетание XHR и Streams API обеспечит эффективную потоковую передачу XHR в браузере. Однако Streams API все еще активно обсуждается и пока недоступен ни в одном браузере. Итак, с этим мы застряли, верно? Ну, не совсем. Как мы отмечали ранее, потоковая загрузка с XHR невозможна, но у нас есть ограниченная поддержка потоковой загрузки с XHR:

Этот пример будет работать в большинстве современных браузеров. Тем не менее, производительность не велика, и есть большое количество предостережений и ошибок реализации:

  • Обратите внимание, что мы вручную отслеживаем смещение для видимых байтов, а затем вручную нарезаем данные: responseText буферизует полный ответ! Для небольших передач это может не быть проблемой, но для больших загрузок, особенно на устройствах с ограниченным объемом памяти, таких как мобильные телефоны, это проблема. Единственный способ освободить буферизованный ответ — завершить запрос и открыть новый.
  • Частичный ответ можно прочитать только из responseText , который ограничивает нас только текстовыми переводами. Невозможно прочитать частичный ответ двоичной передачи.
  • После считывания частичных данных мы должны определить границы сообщений: логика приложения должна определить свой собственный формат данных, а затем буферизовать и проанализировать поток для извлечения отдельных сообщений.
  • Браузеры различаются тем, как они буферизуют полученные данные: некоторые браузеры могут сразу выдавать данные, в то время как другие могут буферизовать небольшие ответы и выдавать их большими порциями.
  • Браузеры различаются тем, какие типы контента они позволяют читать постепенно — например, некоторые разрешают «текст/html», а другие будут работать только с «application/x-javascript».

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

Примечание

Не нужно отчаиваться! Хотя XHR может не соответствовать критериям, у нас есть другие транспорты, оптимизированные для потоковой передачи: Server-Sent Events предлагает удобный API для потоковой передачи текстовых данных с сервера на клиент, а WebSocket предлагает эффективную двунаправленную потоковую передачу для обоих двоичные и текстовые данные.

Уведомления и доставка в реальном времени

XHR обеспечивает простой и эффективный способ синхронизации обновлений клиента с сервером: при необходимости клиент отправляет запрос XHR для обновления соответствующих данных на сервере. Однако та же задача, но в обратном порядке, гораздо сложнее. Если данные обновляются на сервере, как сервер уведомляет клиента?

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

Примечание

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

Опрос с помощью XHR

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

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

  • Каждый запрос XHR является автономным запросом HTTP, и в среднем HTTP требует около 800 байт служебных данных (без файлов cookie HTTP) для заголовков запроса/ответа.
  • Периодические проверки работают хорошо, когда данные поступают через предсказуемые интервалы. К сожалению, предсказуемые темпы прибытия являются исключением, а не нормой. Следовательно, периодический опрос приведет к дополнительным задержкам между сообщением, доступным на сервере, и его доставкой клиенту.
  • Если тщательно не продумать опрос, он часто становится дорогостоящим анти-шаблоном производительности в беспроводных сетях; см. Устранение периодической и неэффективной передачи данных. Пробуждение радио потребляет много энергии батареи!

Каков оптимальный интервал опроса? Нет ни одного. Частота зависит от требований приложения, и существует неотъемлемый компромисс между эффективностью и задержкой сообщений. В результате опрос хорошо подходит для приложений с длительными интервалами опроса, поступлением новых событий с предсказуемой скоростью и большими передаваемыми полезными данными. Эта комбинация компенсирует дополнительные накладные расходы HTTP и минимизирует задержки доставки сообщений.

Длительный опрос с XHR

Проблема с периодическим опросом заключается в том, что существует вероятность множества ненужных и пустых проверок. Имея это в виду, что, если мы немного изменим (рис. 15-1) рабочий процесс опроса: вместо того, чтобы возвращать пустой ответ, когда обновления недоступны, мы могли бы оставить соединение бездействующим, пока не будет доступно обновление?

Рисунок 15-1. Задержка опроса (слева) и долгого опроса (справа)

Примечание

Метод использования долго удерживаемого HTTP-запроса («зависший GET»), позволяющий серверу передавать данные в браузер, широко известен как « Комета. Однако вы также можете встретить его под другими именами, такими как «обратный AJAX», «AJAX push» и «HTTP push».

Удерживая соединение открытым до тех пор, пока не будет доступно обновление (длительный опрос), данные могут быть отправлены клиенту немедленно, как только они станут доступны на сервере. В результате длительный опрос предлагает наилучший сценарий задержки сообщений, а также устраняет пустые проверки, что снижает количество запросов XHR и общие накладные расходы на опрос. Как только обновление доставлено, длинный запрос завершается, и клиент может выдать другой длинный запрос и ждать следующего доступного сообщения:

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

С другой стороны, обсуждение заголовков требует более детального рассмотрения. Во-первых, обратите внимание, что каждое доставленное сообщение требует одних и тех же HTTP-заголовков; каждое новое сообщение представляет собой отдельный HTTP-запрос. Однако если скорость поступления сообщений высока, то при длительном опросе будет выдано больше запросов XHR, чем при периодическом опросе!

Длительный опрос динамически адаптируется к скорости поступления сообщений, сводя к минимуму задержку сообщений, что может вам понравиться или не понравиться. Если существует некоторая терпимость к задержке сообщений, то опрос может быть более эффективным транспортом — например, если скорость обновления высока, то опрос обеспечивает простой механизм «агрегации сообщений», который может уменьшить количество запросов и увеличить время работы от батареи на мобильные телефоны.

Примечание

На практике не все сообщения имеют одинаковый приоритет или требования к задержке. В результате вы можете рассмотреть сочетание стратегий: агрегировать низкоприоритетные обновления на сервере и инициировать немедленную доставку высокоприоритетных обновлений; см. Nagle и Efficient Server Push.

Варианты использования и производительность XHR

XMLHttpRequest — это то, что позволило нам совершить скачок от создания страниц к созданию интерактивных веб-приложений в браузере. Во-первых, он обеспечивает асинхронную связь внутри браузера, но, что не менее важно, упрощает процесс. Отправка и управление HTTP-запросом по сценарию занимает всего несколько строк кода JavaScript, а браузер обрабатывает все остальное:

  • Браузер форматирует HTTP-запрос и анализирует ответ.
  • Браузер применяет соответствующие политики безопасности (тот же источник).
  • Браузер обрабатывает согласование содержимого (например, gzip).
  • Браузер обрабатывает кэширование запросов и ответов.
  • Браузер обрабатывает аутентификацию, перенаправления и многое другое…

Таким образом, XHR является универсальным и высокопроизводительным транспортом для любых передач, которые следуют циклу HTTP-запрос-ответ. Нужно получить ресурс, который требует аутентификации, должен быть сжат во время передачи и должен быть кэширован для будущих поисков? Обо всем этом и многом другом заботится браузер, позволяя нам сосредоточиться на логике приложения!

Однако у XHR есть и свои ограничения. Как мы видели, потоковая передача никогда не была официальным вариантом использования в стандарте XHR, а поддержка ограничена: потоковая передача с XHR неэффективна и неудобна. Разные браузеры ведут себя по-разному, и эффективная бинарная потоковая передача невозможна. Короче говоря, XHR не подходит для потоковой передачи.

Точно так же не существует наилучшей стратегии доставки обновлений в реальном времени с помощью XHR. Периодический опрос влечет за собой высокие накладные расходы и задержки сообщений. Длительный опрос обеспечивает низкую задержку, но все же имеет те же накладные расходы на сообщение; каждое сообщение является собственным HTTP-запросом. Чтобы иметь как низкую задержку, так и низкие накладные расходы, нам нужна потоковая передача XHR!

В результате, хотя XHR и является популярным механизмом доставки «в реальном времени», он может оказаться не самым эффективным транспортом для работы. Современные браузеры поддерживают как более простые, так и более эффективные варианты, такие как Server-Sent Events и WebSocket. Следовательно, если у вас нет конкретной причины, по которой требуется опрос XHR, используйте их.

javascript Promise loop и XHR · GitHub

javascript Promise loop и XHR

Этот файл содержит двунаправленный текст Unicode, который может быть интерпретирован или скомпилирован не так, как показано ниже. Для просмотра откройте файл в редакторе, который показывает скрытые символы Unicode. Узнайте больше о двунаправленных символах Unicode

Показать скрытые символы

функция toDataUrl(url) {
вернуть новое обещание (функция (выполнить, отклонить) {
переменная xhr = новый XMLHttpRequest()
xhr.responseType = ‘клякса’
xhr.onload = функция (e) {
если (e.target.status === 200) {
var reader = новый FileReader()
reader. onloadend = функция (e) {
выполнить(e.target.result)
}
читатель.readAsDataURL(xhr.ответ)
} еще {
отклонить(е)
}
}
xhr.open(‘GET’, URL-адрес)
xhr.send()
})
}
var p1 = toDataUrl(‘.

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

Ваш адрес email не будет опубликован. Обязательные поля помечены *