与Web服务器通讯 - Comet

  • XMLHttpRequest:可以从客户端发送请求到服务器端而且获得响应。一个小demo在这里
    但XHR不适合快速来回发送消息(如聊天室),而且没法将这一次调用和下一次调用联系起来(每次发起请求,服务器都要肯定请求来自何方)。html

  • 轮询:浏览器按期向服务器发送消息并接受服务器回答是否有数据更新。(考虑轮询间隔时间过长/太短的问题)html5

  • COMET(长轮询):在每次请求的时候,服务器端保持该链接在一段时间内处于打开状态,而不是在响应完成以后当即关闭。
    在打开状态的这一段时间里,有数据更新能够当即获得响应。
    上一个长链接关闭以后,浏览器当即打开一个新的长链接继续请求。git

  • COMET(流):浏览器向服务器发送一个请求,而服务器保持链接打开,而后周期性向浏览器发送数据。github

  • Server-Sent events:适合服务器端向客户端不断的数据推送,更容易实现了comet。但整个通讯彻底单向,没法知道浏览器是否响应。web

  • WebSocket:浏览器可以保持对Web服务器打开的链接,从而与服务器长时间交换数据。适合聊天室、大型多人游戏、端到端写做工具等。chrome

Comet

咱们一般说 Ajax 是一种页面向服务器请求数据的技术,那么 Comet 就是一种服务器向页面推送数据的技术,让信息以近乎实时地推送到页面上。跨域

两种实现 Comet 的方式:浏览器

长轮询(long polling)

  1. 先说说短轮询的方式:
    浏览器向服务器发出请求,打开链接,看有没有更新的数据,没有就返回空;好,一次链接关闭。
    间隔一个轮询时间周期,浏览器又再次发出请求,再看有没有更新数据,如此反复。
    可见,这种模式效率不高,若是大多数状况下没有数据,仍是得不断发送请求。
    这种实现方式很容易想到的就是 XHR + setTimeout。缓存

  2. 鉴于这样的浪费,因而有了改善的方案——长轮询:
    浏览器发起一个请求,而后服务器一直打开链接,知道有数据更新可发送,再返回数据,关闭链接。
    随后又发送一个新的请求到服务器,不断重复这一过程。
    可见,这种模式减小了http请求的次数,优化了性能。服务器

  3. But,果服务端的数据变动很是频繁的话,这种机制和定时轮询比较起来没有本质上的性能的提升。
    它们都有一个共同点:在浏览器接收数据,先对服务器发出请求。最大区别是服务器如何发送数据(当即发送/等待发送)。

流(Http Streaming)

  • 流的工做过程:
    浏览器向服务器发送一个请求,而服务器保持链接打开,而后周期性向浏览器发送数据。
    这个过程,链接不会关闭。这就是流不一样于轮询的地方:它在页面的整个生命周期中只使用了一个http链接。
    实现方式很容易想到:利用 XHR,经过 readystatechange 事件并检测 readyState 是否为3进行操做。

  • 客户端实现:

<script>
    // comet http streaming 的实现
      function createStreamingClient(url, progress, finished) {
        var xhr = new XMLHttpRequest(),
            received = 0;

        xhr.open("get", url, true);
        xhr.onreadystatechange = function() {
          var result;

          if (xhr.readyState == 3) {
            result = xhr.responseText.substring(received);
            received += result.length;

            progress(result);
          } else if (xhr.readyState == 4) {
            finished(xhr.responseText);
          }
        };

        xhr.send(null);
        return xhr;
      }

      var client = createStreamingClient("http://localhost:3000/streaming", function(data) {
                      alert("received:" + data);
                   }, function(data) {
                      alert("done");
                   });
    </script>
  • 服务器端实现:
var http = require("http");
var url = require("url");

http.createServer(start).listen(3000);

function start(req, res) {

    res.writeHead(200, {  
        'Access-Control-Allow-Origin': '*',
        'Content-Type': 'text/html'
    });

    var count = 0;  
    var sid = setInterval(function(){  
        res.write(Math.random() + "");

        if (++count == 5) {
            clearInterval(sid);
            res.end();
        }
    }, 1000);
}

'Content-Type': 'text/html'主要是为了解决在chrome下输出数据太少被缓存起来的问题。

这种实现方式,有兼容问题,须要针对不一样的浏览器设计不一样的方案来改进用户体验(IE)。
IE 的实现是经过iframe来处理:

  • 一般就是在客户端的页面使用一个隐藏的窗口向服务端发出一个长链接的请求。服务器端接到这个请求后做出回应并不断更新链接状态以保证客户端和服务器端的链接不过时。经过这种机制能够将服务器端的信息源源不断地推向客户端。

参考《试试跨域通讯》

相关文章
相关标签/搜索