Реализация самовосстанавливающегося объекта XMLHttpRequest - PullRequest
1 голос
/ 28 декабря 2008

Я пытаюсь реализовать кометное длинное соединение с использованием объекта XMLHttpResponse. Идея состоит в том, чтобы поддерживать открытое соединение с сервером, который отправляет данные, когда они доступны (поддельное нажатие). Как только объект XHR завершится, мне нужно создать новый объект, чтобы дождаться свежих данных.

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

window.onload = function(){
    XHR.init();
}


XHR = {
    init: function() {
        this.xhr = new XMLHttpRequest();
        this.xhr.open( "GET", "proxy.php?salt="+Math.round( Math.random()*10000 ), true );
        this.xhr.onreadystatechange = this.process.bind( this );
        this.xhr.send( null );
    },
    process: function() {
        if( this.xhr.readyState == 4 ) {

            // firebug console
            console.log( this.xhr.responseText );

            // ** Attempting to create new XMLHttpRequest object to
            // replace the one that's just completed
            // doesn't work without the timeout
            setTimeout( function() { this.init() }.bind( this ), 1000 );
        }
    }
}


Function.prototype.bind = function( obj ) {
    var method = this;
    return function() {
        return method.apply( obj, arguments );
    }
}


// proxy.php - a dummy that keeps the XHR object waiting for a response
<?php
$rand = mt_rand( 1, 10 );
sleep( $rand );
echo date( 'H:i:s' ).' - '.$rand;

Я думаю, что проблема может заключаться в том, что вы не можете удалить объект (xhr) из его собственного обработчика событий (процесса), как здесь. особенно потому, что «this» в обработчике связано с объектом (XHR), который содержит объект (xhr), который я пытаюсь удалить. Вроде круговой!

Кто-нибудь может помочь? Приведенный выше пример является самым близким, который я могу получить.

Ответы [ 7 ]

1 голос
/ 28 декабря 2008

Просто используйте jquery и сделайте что-то вроде этого:

  function getData() {
    $.getJSON(someUrl, gotData);
  }

  // Whenever a query stops, start a new one.
  $(document).ajaxStop(getData, 0);
  // Start the first query.
  getData();

Мои slosh примеры делают это (поскольку это в значительной степени кометный сервер).

0 голосов
/ 07 февраля 2016

Просто добавьте xhr = null в функцию init. xhr будет назначено новое соединение, и, следовательно, оно не примет предыдущего значения HTTPRequest.

init: function() {
        xhr = null;
        this.xhr = new XMLHttpRequest();
        this.xhr.open( "GET", "proxy.php?salt="+Math.round( Math.random()*10000 ), true );
        this.xhr.onreadystatechange = this.process.bind( this );
        this.xhr.send( null );
    },
0 голосов
/ 28 декабря 2008

Возможно, вам будет проще реализовать повторное использование, добавив метод abort():

XHR = {
    init: function() {
        if (!this.xhr) { // setup only once
            this.xhr = new XMLHttpRequest();
            this.xhr.onreadystatechange = this.process.bind( this );
        }
        this.xhr.abort(); // reset xhr
        this.xhr.open(/*...*/);
        this.xhr.send(null);
    },
    process: function() {
        if( this.xhr.readyState == 4 ) {

            // firebug console
            console.log( this.xhr.responseText );

            // start next round
            this.init();
        }
    }
};

@ meouw [комментарий]

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

0 голосов
/ 28 декабря 2008

Вы, вероятно, вообще не должны использовать XMLHTTPRequest для этого.

Несколько лет назад, задолго до того, как XMLHTTPRequest был известен, я создал программу чата, которая будет использоваться в обычном браузере. Окно с чатом было в фрейме, где данные берутся из cgi-скрипта, который никогда не заканчивался. Всякий раз, когда появлялись новые данные, я просто отправлял их, и они немедленно отображались на клиенте.

Полагаю, сегодня вы можете использовать нечто подобное:

  • Создайте на своей странице функцию, которая будет выполнять обновление.
  • Создайте IFRAME, вы можете сделать его невидимым, если хотите
  • Установите источник IFRAME для вашего скрипта, который генерирует данные
  • Данные могут быть заключены в SCRIPT-теги. Если я правильно помню, браузеры требуют иметь все содержимое тега сценария, прежде чем пытаться его оценить. Вызовите функцию обновления:

    <script type="text/javascript">myupdate("mydata");</script> 
    
  • Даже если вам нечего отправлять, отправляйте пробел каждые 5 секунд или около того, чтобы сбросить время ожидания в браузере.
  • Если я правильно помню, вам нужно было отправить около 1К данных в начале транзакции, чтобы заполнить буфер предварительной выборки в браузере (может быть, в сегодняшних браузерах его нужно увеличить)
0 голосов
/ 28 декабря 2008

@ сту

В этом приложении время отклика является ключевым - на самом деле важно, чтобы все клиенты обновлялись одновременно (или как можно ближе)

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

Если используется опрос, он должен быть очень коротким ~ 100 мс, что приведет к огромному количеству ненужных запросов (что будет дорого для маленького сервера сокетов php, который я собрал вместе - я знаю, я знаю, что Python будет быть лучше для сервера, но я не знаю этого достаточно хорошо)

0 голосов
/ 28 декабря 2008

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

0 голосов
/ 28 декабря 2008

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

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