XMLHttpRequest:可以从客户端发送请求到服务器端而且获得响应。一个小demo在这里
但XHR不适合快速来回发送消息(如聊天室),而且没法将这一次调用和下一次调用联系起来(每次发起请求,服务器都要肯定请求来自何方)。html
轮询:浏览器按期向服务器发送消息并接受服务器回答是否有数据更新。(考虑轮询间隔时间过长/太短的问题)html5
COMET(长轮询):在每次请求的时候,服务器端保持该链接在一段时间内处于打开状态,而不是在响应完成以后当即关闭。
在打开状态的这一段时间里,有数据更新能够当即获得响应。
上一个长链接关闭以后,浏览器当即打开一个新的长链接继续请求。git
COMET(流):浏览器向服务器发送一个请求,而服务器保持链接打开,而后周期性向浏览器发送数据。github
Server-Sent events:适合服务器端向客户端不断的数据推送,更容易实现了comet。但整个通讯彻底单向,没法知道浏览器是否响应。web
WebSocket:浏览器可以保持对Web服务器打开的链接,从而与服务器长时间交换数据。适合聊天室、大型多人游戏、端到端写做工具等。chrome
咱们一般说 Ajax 是一种页面向服务器请求数据的技术,那么 Comet 就是一种服务器向页面推送数据的技术,让信息以近乎实时地推送到页面上。跨域
两种实现 Comet 的方式:浏览器
先说说短轮询的方式:
浏览器向服务器发出请求,打开链接,看有没有更新的数据,没有就返回空;好,一次链接关闭。
间隔一个轮询时间周期,浏览器又再次发出请求,再看有没有更新数据,如此反复。
可见,这种模式效率不高,若是大多数状况下没有数据,仍是得不断发送请求。
这种实现方式很容易想到的就是 XHR + setTimeout。缓存
鉴于这样的浪费,因而有了改善的方案——长轮询:
浏览器发起一个请求,而后服务器一直打开链接,知道有数据更新可发送,再返回数据,关闭链接。
随后又发送一个新的请求到服务器,不断重复这一过程。
可见,这种模式减小了http请求的次数,优化了性能。服务器
But,果服务端的数据变动很是频繁的话,这种机制和定时轮询比较起来没有本质上的性能的提升。
它们都有一个共同点:在浏览器接收数据,先对服务器发出请求。最大区别是服务器如何发送数据(当即发送/等待发送)。
流的工做过程:
浏览器向服务器发送一个请求,而服务器保持链接打开,而后周期性向浏览器发送数据。
这个过程,链接不会关闭。这就是流不一样于轮询的地方:它在页面的整个生命周期中只使用了一个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来处理:
参考《试试跨域通讯》