Статьи

Внедрение технологии Push с использованием событий, отправляемых сервером

Выполнение Ajax-вызовов с использованием объекта XmlHttpRequest является хорошо отработанным методом генерации динамических запросов к серверу. Однако Ajax не позволяет серверу напрямую инициировать передачу данных клиенту — метод, называемый push-технологией . Вот тут -то и появляется API событий, отправленных сервером . Специализируясь на технологии push, отправленные сервером события передают данные клиентам в виде непрерывного потока, называемого потоком событий , по соединению, которое остается открытым. И, поддерживая открытое соединение, устраняются накладные расходы на повторное установление нового соединения.

Сравнение с WebSockets

Многие люди совершенно не знают о существовании событий, отправленных сервером. Это потому, что их часто затмевает более мощный API WebSockets . В то время как WebSockets разрешают двунаправленную полнодуплексную связь между клиентом и сервером, отправленные сервером события позволяют отправлять клиенту сообщения только с сервера. Приложения, которые требуют производительности почти в реальном времени или двусторонней связи, вероятно, лучше подходят для WebSockets.

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

Обнаружение поддержки

Отправленные сервером события относительно хорошо поддерживаются, и Internet Explorer является единственным основным браузером, который еще не поддерживает их . Однако, пока IE отстает, по-прежнему необходимо обеспечить обнаружение функций. На стороне клиента отправляемые сервером события реализуются с помощью объекта EventSource — свойства глобального объекта. Следующая функция определяет, доступен ли конструктор EventSource в браузере. Если функция возвращает true , то могут использоваться отправленные сервером события. В противном случае следует использовать запасной механизм, такой как длинный опрос.

 function supportsSSE() { return !!window.EventSource; } 

соединительный

Чтобы подключиться к потоку событий, вызовите конструктор EventSource , как показано ниже. Вы должны указать URL-адрес потока событий, на который вы пытаетесь подписаться. Конструктор автоматически позаботится об открытии соединения.

 EventSource(url); 

Onopen обработчик событий

Когда соединение установлено, onopen обработчик события onopen . Обработчик события принимает событие open как единственный аргумент. Общий onopen события onopen показан в следующем примере.

 source.onopen = function(event) { // handle open event }; 

Обработчики событий addEventListener() также могут быть написаны с использованием addEventListener() . Этот альтернативный синтаксис предпочтительнее onopen поскольку он позволяет нескольким обработчикам присоединяться к одному и тому же событию. Предыдущий onopen события onopen был переписан ниже с использованием addEventListener() .

 source.addEventListener("open", function(event) { // handle open event }, false); 

Получение сообщений

Клиент интерпретирует поток событий как последовательность событий message DOM. Каждое событие, полученное с сервера, вызывает onmessage обработчика события onmessage . Обработчик onmessage принимает событие message качестве единственного аргумента. В следующем примере создается onmessage события onmessage .

 source.onmessage = function(event) { var data = event.data; var origin = event.origin; var lastEventId = event.lastEventId; // handle message }; 

Событие message содержит три важных свойства — data , origin и lastEventId . Как следует из названия, data содержат фактические данные сообщения в виде строки. Данные могут быть строкой JSON , которую можно передать в метод JSON.parse() . Свойство origin содержит окончательный URL-адрес потока событий после любых перенаправлений. Источник должен быть проверен, чтобы убедиться, что сообщения принимаются только из ожидаемых источников. Наконец, свойство lastEventId содержит идентификатор последнего сообщения, увиденного в потоке событий. Сервер может прикреплять идентификаторы к отдельным сообщениям, используя это свойство. Если идентификатор никогда не был виден, тогда lastEventId будет пустой строкой.

onmessage события onmessage также может быть написан с использованием addEventListener() . В следующем примере показан предыдущий onmessage события onmessage , переписанный для использования addEventListener() .

 source.addEventListener("message", function(event) { var data = event.data; var origin = event.origin; var lastEventId = event.lastEventId; // handle message }, false); 

Названные события

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

 source.addEventListener("foo", function(event) { var data = event.data; var origin = event.origin; var lastEventId = event.lastEventId; // handle message }, false); 

Обработка ошибок

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

 source.onerror = function(event) { // handle error event }; 

Конечно, onerror события onerror также может быть переписан с использованием addEventListener() , как показано ниже.

 source.addEventListener("error", function(event) { // handle error event }, false); 

Отсоединение

Соединение EventSource может быть прервано клиентом в любое время, вызвав метод close() . Синтаксис для close() показан ниже. Метод close() не принимает никаких аргументов и не возвращает никакого значения.

 source.close(); 

Состояния подключения

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

  • Соединение — когда объект EventSource создан, он изначально переходит в состояние соединения. В течение этого времени соединение еще не установлено. EventSource также перейдет в состояние соединения, если установленное соединение потеряно. Значение readyState для EventSocket в состоянии соединения равно 0. Это значение определяется как константа EventSource.CONNECTING .
  • Открыто — Установленное соединение считается открытым. Объекты EventSource в открытом состоянии могут получать данные. Значение readyState равное 1, соответствует открытому состоянию. Это значение определяется как константа EventSource.OPEN .
  • Закрыто — считается, что EventSource находится в закрытом состоянии, если соединение не установлено и оно не пытается восстановить соединение. Это состояние обычно вводится путем вызова метода close() . EventSource в закрытом состоянии имеет значение readyState равное 2. Это значение определяется как константа EventSource.CLOSED .

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

 switch (source.readyState) { case EventSource.CONNECTING: // do something break; case EventSource.OPEN: // do something break; case EventSource.CLOSED: // do something break; default: // this never happens break; } 

Вывод

В этой статье рассматривается клиентский аспект событий, отправляемых сервером. Если вы хотите узнать больше о событиях, отправленных сервером, я рекомендую прочитать Серверную часть событий, отправляемых сервером . Я также написал дополнительную статью о событиях, отправленных сервером, в Node.js. Наслаждайтесь!