实现自动重置XMLHttpRequest对象

时间:2008-12-27 22:22:26

标签: javascript ajax xmlhttprequest

我正在尝试使用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 个答案:

答案 0 :(得分:1)

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

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

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

我的slosh示例执行此操作(因为它几乎是一个彗星服务器)。

答案 1 :(得分:0)

你正在做的是有效的民意调查,为什么要让它变得比它需要的更复杂,并且只是每隔几秒轮询一次?或者每一秒,你真正节省了多少时间,这是非常重要的,如果你有很多用户,你将会在服务器端捆绑大量的套接字。

答案 2 :(得分:0)

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

答案 3 :(得分:0)

@stu

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

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

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

答案 4 :(得分:0)

你可能根本不应该使用XMLHTTPRequest。

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

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

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

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

答案 5 :(得分: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()没有解决)或者你没有标记先前请求发送的内容(重发)每次都是相同的数据。)

答案 6 :(得分:0)

只需在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 );
    },