Ajax是一種從頁面向服務器請求數據的技術,Comet則是一種服務器向頁面推送數據的技術,它能夠讓信息近乎實時地被推送到頁面上。
有兩種實現Comet的方式:長輪詢和流。
長輪詢是瀏覽器定時向服務器發送請求,然后服務器一直保持連接打開,直到有數據可發送。發送完數據后,瀏覽器關閉連接,隨即發起一個新的請求。

短輪詢與長輪詢的區別是,服務器接收到請求后,是否立即發送響應。短輪詢是服務器會立即發送響應,無論數據是否有效。而長輪詢是等待發送響應。所有瀏覽器都支持輪詢,使用xhr對象和setTimeOut()就能實現。
HTTP流,瀏覽器向服務器發送一個請求,而服務器保持連接打開,然后周期性地向瀏覽器發送數據。
在Firefox\Safari\Opera\Chrome中,通過偵聽readystatechange事件及檢測readyState屬性的值是否為3,就可以實現HTTP流。當readyState值變為3時,responseText屬性中就會保存就收到的所有數據,此時,就需要比較此前接收到的數據,決定從什么位置開始取得最新的數據。代碼如下:
1 function createStreamingClient(url,progress,finished){ 2 var xhr = new XMLHttpRequest(),received = 0; 3 xhr.open("get",url,true); 4 xhr.onreadystatechange = function(){ 5 var result; 6 if(xhr.readyState == 3){ 7 result = xhr.responseText.substring(received); 8 received += result.length; 9 10 progress(result); 11 12 }else if(xhr.readyState == 4){ 13 finished(xhr.responseText); 14 } 15 16 }; 17 xhr.send(null); 18 19 return xhr; 20 } 21 22 var client = createStreamingClient("streaming.php",function(data){ 23 alert("received:"+data); 24 },function(data){ 25 alert("done!"); 26 });
SSE(Server-Sent Events,服務器發送事件)用於創建到服務器的單向連接,服務器通過這個連接可以發送任意數量的數據。服務器響應的MIME類型必須是text/even-stream,而且是瀏覽器中的JavaScript API能解析格式輸出。SSE支持短輪詢、長輪詢和HTTP流,而且能在斷開連接時自動確定何時重新連接。
支持SSE的瀏覽器有Firefox 6+、Safari5+、Opera11+、Chrome和iOS4+版Safari。
1、SSE API,創建EventSource對象,並傳入一個入口點。傳入的url必須與創建對象的頁面同源(相同的URL模式、域及端口)。
var source = new EventSource("myevents.php");
EventSource的實例有個readyState屬性,值為0表示正連接到服務器,為1表示打開了連接,為2表示關閉了連接。
包含三個事件,open:在建立連接時觸發,message:在從服務器接收到新事件時觸發,error:在無法建立連接時觸發。
source.onmessage = function(event){ var data = event.data;//服務器返回的數據以字符串形式保存在event.data中 //... };
默認情況下,EventSource對象會保持與服務器的活動連接。如果連接斷開,還會重新連接,適合長輪詢和HTTP流。立即斷開不再重新連接,使用close()。
source.close();
2、事件流,服務器事件會通過一個持久的HTTP響應發送,這個響應的MIME類型為text/event-stream。響應的格式是純文本。
WebSocket,是一種與服務器進行全雙工、雙向通信的信道。在JavaScript中創建了WebSocket之后,會有一個HTTP請求發送到瀏覽器以發起連接。在取得服務器響應后,建立的連接會使用HTTP升級從HTTP協議交換為Web Socket協議。
websocket使用了自定義的協議,使用的URL模式也有所改變。未加密的連接不再是http://,而是ws://;加密的連接不是https://,而是wss://。
使用自定義的協議好處是,能夠在客戶端和服務器之間發送非常少量的數據,而不必擔心HTTP那樣字節級的開銷。比較適合移動應用。缺點是安全性和協議的一致性,目前支持的瀏覽器有Firefox6+、Safari5+、Chrome和iOS4+版Safari。
1、websocket API,創建一個實例,傳入絕對路徑的url。同源策略對websocket不適用。
var socket = new WebSocket("ws://www.example.com/server.php");
實例化websocket對象后,瀏覽器就會馬上嘗試創建連接。readyState屬性表示當前狀態,值如下:
- WebSocket.OPENING(0),正在建立連接
- WebSocket.OPEN(1),已經建立連接
- WebSocket.CLOSING(2),正在關閉連接
- WebSocket.CLOSE(3),已經關閉連接
2、發送和接收數據,只能發送純文本數據,對復雜的數據結構需要進行序列化。服務器發來消息時,就會觸發message事件。
socket.send("hello!");
socket.onmessage = function(event){
var data = event.data;
//...
};
3、其他事件,open:成功建立連接時觸發,error:在發生錯誤時觸發,連接不能持續,close:關閉連接時觸發。
WebSocket不支持DOM2級事件偵聽器,必須使用DOM0級語法分別定義每個事件處理程序。
socket.onopen = function(){ console.log("Connection established") ; }; socket.onerror = function(){ console.log("Connection error"); }; socket.onclose = function(){ console.log("Connection closed"); };
考慮使用SSE還是Websocket時,首先看是否有自由度建立和維護WebSocket服務器,因為WebSocket協議不同於HTTP協議,現有服務器不能用於WebSocket通信。SSE則可以通過常規HTTP通信。其次,是否需要雙向通信。如果只需要讀取服務器數據,SSE比較容易實現。如果需要雙向通信,WebSocket更好一些。組合XHR和SSE也是能實現雙向通信的。
摘自《JavaScript高級程序設計》
