Кроссбраузерная реализация шаблона HTTP Streaming (push) AJAX

Клиентский запрос веб-страницы с сервера. Затем Клент просит провести дополнительные вычисления; сервер выполняет серию вычислений и отправляет частичные результаты, как только они становятся доступными (текстовый формат, каждая строка содержит отдельный полный элемент). Клиент обновляет веб-страницу (с помощью JavaScript и DOM), используя информацию, предоставленную сервером.

Кажется, это соответствует HTTP Streaming (current version) с сайта Ajaxpatterns.

Вопрос в том, как сделать это кроссбраузерным (независимо от браузера) способом, желательно без использования фреймворков JavaScript или с использованием некоторого легкого фреймворка, такого как jQuery.

Проблема начинается с генерации XMLHttpRequest в кроссбраузерном режиме, но я думаю, что основной момент заключается в том, что не все браузеры правильно реализуют onreadystatechangefrom XMLHttpRequest; не все браузеры вызывают событие onreadystatechange на каждом сбросе сервера (кстати, как заставить сбросить сервер из сценария CGI (в Perl)?). Пример кода на Ajaxpatterns решает эту проблему с помощью таймера; мне следует отказаться от таймера, если я обнаружил частичный ответ от onreadystatechange?


Добавлено 08.11.2009

Текущее решение:
я использую следующую функцию для создания объекта XMLHttpRequest:

function createRequestObject() {
        var ro;
        if (window.XMLHttpRequest) {
                ro = new XMLHttpRequest();
        } else {
                ro = new ActiveXObject("Microsoft.XMLHTTP");
        }
        if (!ro)
                debug("Couldn't start XMLHttpRequest object");
        return ro;
}

Если бы мне пришлось использовать некоторую (желательно облегченную) структуру JavaScript, такую ​​как jQuery, я бы хотел иметь запасной вариант, если пользователь решит не устанавливать jQuery.

Я использую следующий код для запуска AJAX; setInterval используется, потому что некоторые браузеры вызывают onreadystatechange только после того, как сервер закрывает соединение (что может занять несколько десятков секунд), а не сразу после того, как сервер сбрасывает данные (примерно каждую секунду или чаще).

function startProcess(dataUrl) {
        http = createRequestObject();
        http.open('get', dataUrl);
        http.onreadystatechange = handleResponse;
        http.send(null);

        pollTimer = setInterval(handleResponse, 1000);
}

Функция handleResponse - самая сложная, но ее набросок выглядит следующим образом. Можно ли лучше? Как это можно было бы сделать с помощью некоторой облегченной инфраструктуры JavaScript (например, jQuery)?

function handleResponse() {
    if (http.readyState != 4 && http.readyState != 3)
        return;
    if (http.readyState == 3 && http.status != 200)
        return;
    if (http.readyState == 4 && http.status != 200) {
        clearInterval(pollTimer);
        inProgress = false;
    }
    // In konqueror http.responseText is sometimes null here...
    if (http.responseText === null)
        return;

    while (prevDataLength != http.responseText.length) {
        if (http.readyState == 4  && prevDataLength == http.responseText.length)
            break;
        prevDataLength = http.responseText.length;
        var response = http.responseText.substring(nextLine);
        var lines = response.split('\n');
        nextLine = nextLine + response.lastIndexOf('\n') + 1;
        if (response[response.length-1] != '\n')
            lines.pop();

        for (var i = 0; i < lines.length; i++) {
            // ...
        }
    }

    if (http.readyState == 4 && prevDataLength == http.responseText.length)
        clearInterval(pollTimer);

    inProgress = false;
}

person Jakub Narębski    schedule 10.07.2009    source источник
comment
Вы обязательно должны добавить этот пример кода в качестве ответа и пометить его как правильный!   -  person Emil Stenström    schedule 04.01.2012
comment
если пользователь решит не устанавливать jQuery?   -  person Basic    schedule 17.07.2012
comment
Привет, только что наткнулся на ваше решение, но я боюсь, что оно все равно не будет работать с IE, поскольку, когда вы попытаетесь получить responseText, пока запросы еще не завершены, вы получите следующее сообщение : Данные, необходимые для выполнения этой операции, пока недоступны.   -  person Tomer Peled    schedule 30.11.2013


Ответы (2)


Решение, с которым вы связались, на самом деле вообще не AJAX. Они называют это HTTP Streaming, но по сути это просто длинный опрос.

В примере, на который они ссылаются, вы можете легко убедиться с помощью firebug. Включите панель «Сеть» - записей XHR нет, но загрузка исходной страницы занимает чуть более 10 секунд. Это потому, что они негласно используют PHP, чтобы задержать вывод HTML. В этом суть длительного опроса - соединение HTTP остается открытым, а отправляемый периодически HTML - это команды javascript.

Однако вы можете выбрать полностью опрос на стороне клиента с помощью setTimeout () или setInterval ().

Пример jQuery

<script type="text/javascript">
  $(document).ready(function()
  {
    var ajaxInterval = setInterval( function()
    {
      $.getJSON(
        'some/servie/url.ext'
        , { sample: "data" }
        , function( response )
          {
            $('#output').append( response.whatever );          
          }
      );
    }, 10000 );  
  });
</script>
person Peter Bailey    schedule 11.07.2009
comment
Не совсем то, что я хочу. Расчет на сервере генерирует вывод в текстовом формате. С помощью XHR я могу получить этот ответ прямо в клиенте (onreadystatechange при сбросе / таймере) и редактировать веб-страницу в соответствии с частичными данными, которые я получаю. - person Jakub Narębski; 11.07.2009
comment
Что не то, что тебе нужно? Долгий опрос? Я не рекомендую ни один из методов - я просто говорю вам, какие у вас есть варианты. - person Peter Bailey; 11.07.2009
comment
Если вы хотите использовать длинный пул (Comet), вам следует подумать об использовании программного обеспечения сервера Meteor, потому что Apache не предназначен для такого рода вещей. И еще есть библиотека javascript, которая обрабатывает почти все за вас, я просто не могу вспомнить ее название, опубликую позже. - person usoban; 11.07.2009

Я бы посмотрел на орбиту

Они используют несколько реализаций транспорта комет, которые выбирают на основе конфигурации и анализа браузера.

См. http://orbited.org/svn/orbited/trunk/daemon/orbited/static/Orbited.js

и найдите "Orbited.CometTransports"

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

person Community    schedule 15.07.2009