【问题标题】:how does long polling work javascript?长轮询如何工作 javascript?
【发布时间】:2013-09-04 20:00:55
【问题描述】:

您好,我知道在长轮询中,您会长时间保持与服务器的连接打开,直到您从服务器获得响应,然后再次轮询并等待下一个响应。但是我似乎不明白如何编码。下面有这段代码使用长轮询,但我似乎没有得到它

(function poll(){
$.ajax({ url: "server", success: function(data){
   //update page based on data

}, dataType: "json", complete: poll, timeout: 30000 });
})();

但是这里的连接如何保持打开状态。我知道一旦得到服务器的响应就会再次触发“poll”功能。但是连接是如何保持打开的?

Edit1:- 如果有人也可以在这里解释超时实际上会做什么,那就太好了

【问题讨论】:

  • 可能连接没有保持打开....
  • 如何防止服务器关闭连接。如果请求发送到服务器,它会响应,然后conn会自动关闭
  • @itamecodes:你写你的服务器,让它在有数据响应之前不会响应。
  • 我认为这个人从techoctave.com/c7/posts/… 那里得到了例子,这是一篇似乎没有意义的文章。它两次给出了几乎相同的示例,并说一个不是长轮询!

标签: javascript jquery long-polling


【解决方案1】:

客户端无法强制服务器保持连接打开。 服务器 根本没有关闭连接。服务器将不得不在某个时候说“就是这样,这里没有更多内容了,再见”。在长轮询中,服务器根本不会这样做,并让客户端等待更多数据,随着更新的到来,它会一点一点地流出。这就是长轮询。

在客户端,可以偶尔检查已经收到的数据,而请求还没有完成。这样,数据有时可以通过同一个打开的连接从服务器发送。在您的情况下,这没有完成,success 回调只会在请求完成时触发。它基本上是一种廉价的长轮询形式,其中服务器让客户端等待事件,发送有关此事件的数据,然后关闭连接。客户端将其作为触发器,处理数据,然后重新连接到服务器以等待下一个事件。

【讨论】:

  • 我想我现在明白了.. 能否请您分享一些骨架服务器代码以更清楚一点
  • @itamecodes 一件重要的事情:对于服务器端,您需要设置配置以在超时之前不关闭连接。
  • @itame 一个简单的示例是while (!($data = checkDatabaseForData())) sleep(1); echo $data; - 这取决于您在服务器端使用的语言,像node.js 这样的事件系统将比sleep 优雅得多循环。
  • @deceze 我有一个关于`在长轮询中,服务器根本不会这样做并让客户端等待更多数据的问题...`服务器将如何部分发送响应。例如浏览器将请求发送到服务器,现在如果服务器需要发送多个响应(R1,R2 等)返回。它必须聚合所有内容,然后将其发送回客户端并关闭连接。服务器无法将部分响应 R1 发送到浏览器并保持连接打开以发送进一步的响应 R2。不是吗?
  • @emilly 如果客户端偶尔检查它已经收到的数据,它可以。自从我接触到长轮询的复杂性已经很长时间了,我也不确定实际的实现了。无论如何,所有现代浏览器都支持更好的机制,例如套接字。
【解决方案2】:

我认为让我们难以理解的原因是讨论集中在客户端编程上。

长轮询并非严格意义上的客户端模式,但需要 Web 服务器保持连接打开。

背景:当某事发生或可用时,客户希望 Web 服务器通知我,例如,当有新电子邮件到达时让我知道,而我不必每隔几秒就回去询问一次。

  1. 客户端打开到 Web 服务器上特定 URL 的连接。
  2. 服务器接受连接,打开套接字并将控制分配给处理此连接的任何服务器端代码(例如 java 中的 servlet 或 jsp,或 RoR 或 node/express 中的路由)。
  3. 服务器代码等待事件或信息可用。例如,当一封电子邮件到达时,查看是否有任何“等待连接”是针对特定收件箱的。如果是,则使用适当的数据进行响应。
  4. 客户端接收数据,执行其操作,然后启动另一个轮询请求。

【讨论】:

    【解决方案3】:

    我希望对交错的数据结果做一些事情,其中​​一些结果会立即返回,但最后几个结果可能会在 10-15 秒后返回。我创建了一个快速的小 jQuery hack,但它有点做我想要的(仍然不确定使用它是否有意义):

    (function($) {
        if (typeof $ !== 'function') return;
        $.longPull = function(args) {
            var opts = $.extend({ method:'GET', onupdate:null, onerror:null, delimiter:'\n', timeout:0}, args || {});
            opts.index = 0;
            var req = $.ajaxSettings.xhr();
            req.open(opts.method, opts.url, true);
            req.timeout = opts.timeout;
            req.onabort = opts.onabort || null;
            req.onerror = opts.onerror || null;
            req.onloadstart = opts.onloadstart || null;
            req.onloadend = opts.onloadend || null;
            req.ontimeout = opts.ontimeout || null;
            req.onprogress = function(e) {
                try {
                    var a = new String(e.srcElement.response).split(opts.delimiter);
                    for(var i=opts.index; i<a.length; i++) {
                        try {
                            var data = JSON.parse(a[i]); // may not be complete
                            if (typeof opts.onupdate==='function') opts.onupdate(data, i);
                            opts.index = i + 1;
                        } catch(fx){}
                    }
                }
                catch(e){}
            };
            req.send(opts.data || null);
        };
    })(jQuery);
    

    很大程度上未经测试,但它似乎符合您的想法。不过,我可以想到各种可能出错的方法;-)

    $.longPull({ url: 'http://localhost:61873/Test', onupdate: function(data) { console.log(data); }});
    

    【讨论】:

      【解决方案4】:

      根据要求,这里是一些伪 NodeJS 代码:

      function respond_to_client(res,session,cnt)
      {
          //context: res is the object we use to respond to the client
          //session: just some info about the client, irrelevant here
          //cnt: initially 0
      
          //nothing to tell the client, let's long poll.
          if  (nothing_to_send(res,session)) 
          {
              if (cnt<MAX_LONG_POLL_TIME)
              {
                  //call this function in 100 ms, increase the counter
                  setTimeout(function(){respond_to_client(request_id,res,session,cnt+1)},100);
              }
              else
              {
                  close_connection(res); 
                  //Counter too high.
                  //we have nothing to send and we kept the connection for too long,
                  //close it. The client will open another.
              }
          }
          else 
          {
              send_what_we_have(res);
              close_connection(res);
              //the client will consume the data we sent, 
              //then quickly send another request.
          }
      
          return;
      
      }
      

      【讨论】:

        【解决方案5】:

        仅从该代码看不到它是如何工作的,因为与常规请求的实际区别是在服务器上完成的。

        Javascript 只是发出一个常规请求,但服务器不必立即响应该请求。如果服务器没有任何值得返回的内容(即浏览器等待的更改尚未发生),则服务器只会等待以保持连接打开。

        如果服务器在一段时间内没有任何反应,客户端将超时并发出新请求,或者服务器可以选择返回空结果以保持流程继续。

        【讨论】:

          【解决方案6】:

          连接并非一直保持打开状态。当从服务器收到响应并且服务器关闭连接时,它会自动关闭。在长轮询中,服务器不应该立即发回数据。在 ajax complete(当服务器关闭连接时),新请求被发送到服务器,服务器再次打开一个新连接并开始等待新的响应。

          如前所述,长轮询过程不仅由客户端处理,而且主要由服务器端处理。而且不仅通过服务器脚本(在 PHP 的情况下),而且通过服务器本身,它不会通过超时关闭 “挂起” 连接。

          FWIW,WebSockets 使用与服务器端不断打开的连接,这样可以在不关闭连接的情况下接收和发送回数据。

          【讨论】:

          • 那么这段代码与传统轮询有何不同。顺便说一句,我没有否决这个答案
          • @Rasmus 传统轮询 = AJAX 轮询:请求的网页执行 javascript,它以 定期 间隔(例如 0.5 秒)从服务器请求文件。见 -stackoverflow.com/questions/11077857/…
          【解决方案7】:

          我猜没有人能正确解释为什么我们需要在代码中超时。来自 jQuery Ajax 文档:

          为请求设置超时(以毫秒为单位)。这将覆盖使用 $.ajaxSetup() 设置的任何全局超时。超时时间从 $.ajax 调用开始;如果其他几个请求正在进行中并且浏览器没有可用的连接,则请求可能会在发送之前超时

          超时选项确实不会将下一次执行延迟 X 秒。它只为当前调用设置最大超时。关于超时的好文章 - https://mashupweb.wordpress.com/2013/06/26/you-should-always-add-timeout-to-you-ajax-call-in-jquery/

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-02-03
            • 2011-09-02
            • 1970-01-01
            • 1970-01-01
            • 2014-08-10
            • 2011-03-10
            相关资源
            最近更新 更多