我们知道Ajax是一种页面向服务器请求数据的技术,那么Comet就是一种服务器向页面推送数据的技术,而且能够让信息以近乎实时地推送到页面上,我们常将它称之为“服务器推送”。
用Comet来实现与跨域服务器的通信有两种方式:长轮询(long polling)和流(http streaming)。
长轮询(long polling)
说到长轮询,很容易就会联想到短轮询,短轮询就是不断向服务器发送请求,看看有没有新数据。可以看出这种模式效率不高,如果大多数情况下没有数据,还是得不断发送请求。
为了缓解这个问题,于是就有了长轮询,长轮询将短轮询颠倒了一下。页面发送请求到服务器,服务器一直保持连接打开,直到有数据可发送。数据发送完毕后,浏览器关闭连接。随后又发送一个新的请求到服务器,这一过程会不断重复。
<body>
<button id="btn">发送请求</button>
<div id="result"></div>
<script>
var btn = document.querySelector("#btn"), counter = 1;
var poll = function() {
var xhr = new XMLHttpRequest();
xhr.open('GET', "http://localhost:3000/poll/"+counter, true);
xhr.onreadystatechange = function(){
if(xhr.readyState == 4) {
var res = document.querySelector("#result");
res.innerHTML += xhr.responseText + "<br>";
if(++counter <= 5){
poll();
} else {
counter = 1;
}
}
};
xhr.send(null);
};
btn.onclick = function(){
document.querySelector("#result").innerHTML = "";
poll();
};
</script>
</body>
//服务器代码
app.get("/poll/:id",function (req,res) {
res.append("Access-Control-Allow-Origin","http://localhost:63342");//实现跨域
setTimeout(function () {
res.send("第"+req.params.id+"次请求");
},2000)
})
HTTP流
另外一种实现就是Http Streaming,与之前提到的轮询不同的是,Http Streaming在整个页面生命周期内只使用一个Http连接,具体来说就是。浏览器向服务器发送一个请求,而服务器保持连接打开,然后周期性的向浏览器发送数据。
<body>
<button id="btn">发送请求</button>
<div id="results"></div>
<script>
var btn2 = document.querySelector("#btn");
btn2.onclick = function(){
var client = createClient("http://localhost:3000/stream", function(data){
document.querySelector("#results").innerHTML += "Received:"+data+"<br>";
}, function(data){
document.querySelector("#results").innerHTML += "Done!";
});
}
function createClient(url, process, finished){
var xhr = new XMLHttpRequest(), received = 0;
xhr.open('GET', url, true);
xhr.onreadystatechange = function(){
var result;
if(xhr.readyState == 3){
result = xhr.responseText.slice(received);
received += result.length;
process(result);
} else if(xhr.readyState == 4) {
finished(xhr.responseText);
}
}
xhr.send(null);
return xhr;
}
</script>
</body>
app.get("/stream",function (req,res) {
res.append("Access-Control-Allow-Origin","*");
res.append('Content-Type','text/html');
var count = 0;
var sid = setInterval(function(){
res.write(Math.random()+"");
if(++count == 5){
clearInterval(sid);
res.end();
}
}, 1000);
})