Comet 是一种高级的Ajax技术,实现了服务器向页面实时推送数据的技术,应用场景有体育比赛比分和股票报价等。
实现Comet有两种方式:长轮询与http流
长轮询是短轮询的翻版,短轮询的方式是:页面定时向服务器发送请求,看有没有更新的数据。
而长轮询的方式是,页面向服务器发起一个请求,服务器一直保持tcp连接打开,知道有数据可发送。发送完数据后,页面关闭该连接,随即又发起一个新的服务器请求,在这一过程中循环。
短轮询和长轮询的区别是:短轮询中服务器对请求立即响应,而长轮询中服务器等待新的数据到来才响应,因此实现了服务器向页面推送实时,并减少了页面的请求次数。
http流不同于上述两种轮询,因为它在页面整个生命周期内只使用一个HTTP连接,具体使用方法即页面向浏览器发送一个请求,而服务器保持tcp连接打开,然后不断向浏览器发送数据。
以下为客户端实现长轮询的方法:
var xhr = new XMLHttpRequest(); xhr.onreadystatechange = function(){ if(xhr.readyState == 4){ result = xhr.responseText console.log(result); xhr.open('get', 'test2.php'); //在获得数据后重新向服务器发起请求 xhr.send(null); } } xhr.open('get', 'test2.php'); xhr.send(null);
以下为客户端实现http流的方法:
var xhr = new XMLHttpRequest(); received = 0; //最新消息在响应消息的位置 xhr.onreadystatechange = function(){ if(xhr.readyState == 3){ result = xhr.responseText.substring(received); console.log(result); received += result.length; }else if(xhr.readyState == 4){ console.log("完成消息推送"); } } xhr.open('get', 'test1.php'); xhr.send(null);
以下为服务器端实时推送的实现方法,以php为例:
<?php ini_set('max_execution_time', 10); error_reporting(0); $i = 0; while(true){ //不断推送消息 echo "Number is $i "; ob_flush(); //将php缓存冲出 flush(); //从php缓存中输出到tcp缓存 $i++; sleep(1); } ?>
页面接受到数据效果如下:
另外大多数浏览器实现了SSE(Server-Sent Events,服务器发送事件) API,SSE支持短轮询、长轮询和HTTP流,使用方式如下:
客户端:
var source = new EventSource("test.php"); //生成EventSource对象,url必须同源 var len = 0; source.onopen = function(){ //如果连接断开,还会自动重新连接 console.log("connection opend"); } source.onmessage = function(event){ //event.data返回最新的消息 var data = event.data.substring(0); len = data.length; console.log(data); }
服务器端:
<?php ini_set('max_execution_time', 10); header('Content-type: text/event-stream'); //服务器响应的MIME类型必须是text/event-stream $i = 0; while(true){ echo "data: Number is $i "; //固定格式: 数据必须以data:为前缀 echo " "; //数据以空行,即' '分隔,每一个空行触发一次message事件 ob_flush(); flush(); $i++; sleep(1); } ?>
参考资料: 《javascript 高级程序设计》