JavaScript. Подробное руководство, 6-е издание, стр. 291

<b>if (window.EventSource === undefined) { // Если EventSource не поддерживается,</b>

<b>  window.EventSource = function(url) { // использовать эту его имитацию,</b>

<b>    var xhr; // HTTP-соединение...</b>

<b>    var evtsrc = this: // Используется в обработчиках,</b>

<b>    var charsReceived = 0; // Так определяется появление нового текста</b>

<b>    var type = null; // Для проверки свойства type ответа,</b>

<b>    var data = &quot;&quot;; // Хранит данные сообщения</b>

<b>    var eventName = &quot;message&quot;: // Значение поля type объектов событий</b>

<b>    var lastEventld = &quot;&quot;; // Для синхронизации с сервером</b>

<b>    var retrydelay = 1000: // Задержка между попытками соединения</b>

<b>    var aborted = false: // Установите в true, чтобы разорвать соединение</b>

<b>    // Создать объект XHR</b>

<b>    xhr = new XMLHttpRequest():</b>

<b>    // Определить обработчик события для него</b>

<b>    xhr.onreadystatechange = function() {</b>

<b>      switch(xhr.readyState) {</b>

<b>      case 3: processData(): break; // При получении фрагмента данных</b>

<b>      case 4: reconnectO: break; // По завершении запроса</b>

<b>      }</b>

<b>    };</b>

<b>    // И установить долгоживущее соединение</b>

<b>    connect();</b>

<b>    // Если соединение было закрыто обычным образом, ждать секунду </b>

<b>    // и попробовать восстановить соединение</b>

<b>    function reconnect() {</b>

<b>      if (aborted) return; // He восстанавливать после</b>

<b>                         // принудительного прерывания</b>

<b>      if (xhr.status &gt;= 300) return; </b>

<b>      // He восстанавливать после ошибки</b>

<b>      setTimeout(connect, retrydelay); // Ждать и повторить попытку</b>

<b>    };</b>

<b>    // Устанавливает соединение</b>

<b>    function connect() {</b>

<b>      charsReceived = 0; type = null; xhr.open(&quot;GET&quot;, url); </b>

<b>      xhr.setRequestHeader(“Cache-Control&quot;, &quot;no-cache&quot;);</b>

<b>      if (lastEventld) </b>

<b>        xhr.setRequestHeader(&quot;Last-Event-ID&quot;, lastEventld);</b>

<b>     xhr.send(); </b>

<b>    } </b>

<b>    // При получении данных обрабатывает их и вызывает обработчик onmessage.</b>

<b>    // Эта функция реализует работу с протоколом Server-Sent Events </b>

<b>    function processData() { </b>

<b>      if (!type) { // Проверить тип ответа, если это еще не сделано</b>

<b>        type = xhr.getResponseHeader(’Content-Type’);</b>

<b>        if (type !== &quot;text/event-stream&quot;) {</b>

<b>          aborted = true;</b>

<b>          xhr.abort();</b>

<b>          return; </b>

<b>        } </b>

<b>      } </b>

<b>      // Запомнить полученный объем данных и извлечь только ту часть ответа,</b>

<b>      // которая еще не была обработана,</b>

<b>      var chunk = xhr.responseText.substring(charsReceived);</b>

<b>      charsReceived = xhr.responseText.length; </b>

<b>      // Разбить текст на строки и обойти их в цикле. </b>

<b>      var lines = chunk.replace(/(\r\n|\r|\n)$/,&quot;&quot;).split(/\r\n|\r|\n/); </b>

<b>      for(var і = 0; і &lt; lines.length; i++) { </b>

<b>        var line = lines[i], pos = line.indexOf(&quot;:&quot;), name.value=&quot;&quot;;</b>

<b>        if (pos == 0) continue; // Игнорировать комментарии </b>

<b>        if (pos &gt; 0) { // поле name:value </b>

<b>          name = line.substring(0,pos);</b>

<b>          value = line.substring(pos+1); </b>

<b>          if (value.charAt(O) == &quot; &quot;) value = value.substrings); </b>

<b>        } </b>

<b>        else name = line; // только поле name </b>

<b>        switch(name) { </b>

<b>        case &quot;event&quot;: eventName = value; break; </b>