代码之家  ›  专栏  ›  技术社区  ›  meouw

实现自重置的xmlhttpRequest对象

  •  1
  • meouw  · 技术社区  · 16 年前

    我正在尝试使用xmlhttpresponse对象实现一个Comet风格的长轮询连接。 其思想是保持与服务器的开放连接,当服务器可用时发送数据(假装推送)。一旦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 回复  |  直到 9 年前
        1
  •  1
  •   Dustin    16 年前

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

      function getData() {
        $.getJSON(someUrl, gotData);
      }
    
      // Whenever a query stops, start a new one.
      $(document).ajaxStop(getData, 0);
      // Start the first query.
      getData();
    

    我的 slosh 这样做的例子(因为它几乎是一个Comet服务器)。

        2
  •  0
  •   stu    16 年前

    你要做的是有效地进行投票,为什么要使它比需要的更复杂,并且每隔几秒钟进行一次投票?或者每一秒钟,你到底节省了多少时间,这真的很重要吗?如果你有很多用户的话,你会在服务器端绑上大量的套接字。

        3
  •  0
  •   stu    16 年前

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

        4
  •  0
  •   meouw    16 年前

    @斯图

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

    断开连接的数量将相当有限,最大值约为50,更改之间的间隔可能为几分钟。

    如果使用轮询,则需要非常短的时间~100毫秒,这将导致大量不必要的请求(对于我拼凑在一起的小php socket服务器来说,这将非常昂贵-我知道,我知道python对服务器更好,但我对它的了解不够透彻)

        5
  •  0
  •   Jonathan Lonowski    16 年前

    您可以更轻松地实现重用,将 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
  •   GitaarLAB    10 年前

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

    几年前,早在XMLHttpRequest被发现之前,我就创建了一个聊天程序,在普通浏览器中使用。聊天窗口在一个帧中,数据来自一个从未结束的CGI脚本。每当有新的数据时,我就发送它,它立即显示在客户机上。

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

    • 在页面中创建将执行更新的函数。
    • 创建一个iframe,如果需要,可以使其不可见
    • 将iframe的源设置为生成数据的脚本
    • 数据可以封装在脚本标记中。如果我记得正确的话,浏览器在尝试评估脚本标记之前需要完整的脚本标记内容。调用更新函数:

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

    只要添加 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 );
        },