<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 = ""; // Хранит данные сообщения</b>
<b> var eventName = "message": // Значение поля type объектов событий</b>
<b> var lastEventld = ""; // Для синхронизации с сервером</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 >= 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("GET", url); </b>
<b> xhr.setRequestHeader(“Cache-Control", "no-cache");</b>
<b> if (lastEventld) </b>
<b> xhr.setRequestHeader("Last-Event-ID", 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 !== "text/event-stream") {</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)$/,"").split(/\r\n|\r|\n/); </b>
<b> for(var і = 0; і < lines.length; i++) { </b>
<b> var line = lines[i], pos = line.indexOf(":"), name.value="";</b>
<b> if (pos == 0) continue; // Игнорировать комментарии </b>
<b> if (pos > 0) { // поле name:value </b>
<b> name = line.substring(0,pos);</b>
<b> value = line.substring(pos+1); </b>
<b> if (value.charAt(O) == " ") value = value.substrings); </b>
<b> } </b>
<b> else name = line; // только поле name </b>
<b> switch(name) { </b>
<b> case "event": eventName = value; break; </b>