2

我正在尝试使用 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)。有点圆!

任何人都可以帮忙吗?上面的例子是我能得到的最接近的例子。

4

7 回答 7

1

只需使用 jquery 并执行以下操作:

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

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

我的晃动示例就是这样做的(因为它几乎是一个彗星服务器)。

于 2008-12-28T03:19:01.490 回答
0

你正在做的是有效的轮询,为什么让它比它需要的更复杂,并且每隔几秒钟就轮询一次?或者每一秒,你真正节省了多少时间,它真的那么重要吗,如果你有很多用户,你将在服务器端占用大量的套接字。

于 2008-12-27T22:26:46.383 回答
0

但是要实际尝试回答您的问题,删除不是这个的东西的方法是设置一个计时器来调用一个执行删除的函数,这样,它本身就不会被删除。

于 2008-12-27T22:27:58.270 回答
0

@stu

在这个应用程序中,响应时间是关键 - 实际上重要的是所有客户端都同时更新(或尽可能接近)

关闭连接的数量将相当有限~50max,更改之间的间隔可能是几分钟。

如果使用轮询,它需要非常短~100ms,这将导致大量不必要的请求(这对于我拼凑在一起的小型 php 套接字服务器来说会很昂贵 - 我知道,我知道 python 会更好服务器,但我不太了解)

于 2008-12-27T22:47:24.503 回答
0

您可能根本不应该为此使用 XMLHTTPRequest。

几年前,早在 XMLHTTPRequest 出现之前,我就创建了一个用于普通浏览器的聊天程序。聊天窗口位于数据来自永不结束的 cgi 脚本的框架中。每当有新数据时,我就发送它,它立即显示在客户端。

我想你今天可以使用类似的东西:

  • 在您的页面中创建一个将执行更新的函数。
  • 创建一个 IFRAME,您可以根据需要使其不可见
  • 将 IFRAME 的源设置为生成数据的脚本
  • 数据可以封装在 SCRIPT 标记中。如果我没记错的话,浏览器在尝试评估它之前需要拥有脚本标签的全部内容。调用你的更新函数:

    <script type="text/javascript">myupdate("mydata");</script> 
    
  • 即使您没有要发送的内容,也请每隔 5 秒左右发送一个空格以重置浏览器的超时时间。
  • 如果我没记错的话,你必须在事务开始时发送大约 1K 数据来填充浏览器的预取缓冲区(也许今天的浏览器必须增加这个)
于 2008-12-28T00:02:49.840 回答
0

您可能更容易实现重用,添加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()没有解决),或者您没有标记先前请求发送的内容(每次重新发送相同的数据)。

于 2008-12-28T01:31:57.633 回答
0

只需在函数xhr = null内部添加即可。initxhr被分配一个新的连接,因此不会采用以前的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 );
    },
于 2016-02-07T13:07:45.207 回答