传说中的comet(iframe版)?
comet有两种实现方式:长轮询(long-polling)和iframe流(streaming)。
demo下载:comet-iframe.zip
comet相关资料:http://www.ibm.com/developerworks/cn/web/wa-lo-comet/
之前一篇随笔已经写了长轮询的代码,虽然不知道那是不是就是正确的,因为我感觉就像是普通的ajax,这里写的就是iframe流的方式。
前端代码:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Comet demo</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script type="text/javascript">
var comet = {
connection : false,
iframediv : false,
timer : 0,
initialize: function() {
if (!-[1,]) {
// For IE browsers
comet.connection = new ActiveXObject("htmlfile");
comet.connection.open();
comet.connection.write("<html>");
comet.connection.write("<script>document.domain = '"+document.domain+"'");
comet.connection.write("</html>");
comet.connection.close();
comet.iframediv = comet.connection.createElement("div");
comet.connection.appendChild(comet.iframediv);
comet.connection.parentWindow.comet = comet;
comet.iframediv.innerHTML = "<iframe id='comet_iframe' name='comet_iframe' src='./backend.php'></iframe>";
var comet_iframe = comet.connection.getElementById("comet_iframe");
comet.timer = window.setInterval(function(){
if(comet_iframe.readyState === "complete"){
comet_iframe.src = comet_iframe.src;
}
},1000*65)
}else{
comet.connection = document.createElement('iframe');
comet.connection.onload = function(){
comet.connection.src = comet.connection.src;
}
comet.connection.setAttribute('id','comet_iframe');
comet.connection.setAttribute('src','./backend.php');
comet.connection.style.display = "none";
document.body.appendChild(comet.connection);
}
},
// this function will be called from backend.php
printServerTime: function (time) {
document.getElementById('content').innerHTML = time;
},
onUnload: function() {
if (comet.connection) {
comet.connection = false; // release the iframe to prevent problems with IE when reloading the page
}
}
}
window.onload = function(){
comet.initialize();
}
window.onbeforeunload = function(){
comet.onUnload();
}
</script>
</head>
<body>
<div id="content">The server time will be shown here</div>
</body>
</html>
后台代码:
<?php
header("Cache-Control: no-cache, must-revalidate");
header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
flush();
?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Comet php backend</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>
<body>
<script type="text/javascript">
// KHTML browser don't share javascripts between iframes
var is_khtml = navigator.appName.match("Konqueror") || navigator.appVersion.match("KHTML");
if (is_khtml)
{
var prototypejs = document.createElement('script');
prototypejs.setAttribute('type','text/javascript');
prototypejs.setAttribute('src','prototype.js');
var head = document.getElementsByTagName('head');
head[0].appendChild(prototypejs);
}
// load the comet object
var comet = window.parent.comet;
</script>
<?php
while(1) {
echo '<script type="text/javascript">';
echo 'comet.printServerTime('.time().');';
echo '</script>';
flush(); // used to send the echoed data to the client
sleep(1); // a little break to unload the server CPU
}
?>
</body>
</html>
就像资料里所说的,“在 HTML 页面里嵌入一个隐蔵帧,然后将这个隐蔵帧的 SRC 属性设为对一个长连接的请求,服务器端就能源源不断地往客户端输入数据”,通过iframe里的内容进行长时间的请求,当需要传输内容时通过调用父页面js方法来实现页面展示,以此达到comet所需要的效果。
使用iframe流的一个不足就是在IE、opera、chrome浏览器下,始终会显示下载没完成,并且鼠标及浏览器上的那个圈一直在转动,在IE678下,google的大牛们通过使用“htmlfile”解决了这个问题,IE9我试了,并不支持"htmlfile",当然IE9那个圈已经不转了。但是opera、chrome不支持“htmlfile”,无法解决。
iframe的另一个问题就是请求的超时,我们需要判断当iframe超时时,对其刷新重新建立连接。在普通情况下,我们可以通过iframe的onload事件进行刷新,当iframe连接内容超时时就会触发onload事件。在“htmlfile”下iframe却不支持onload,但是能读取到iframe的readyState,当readyState为complete时即表示请求超时,所以我们可以通过setInterval来判断iframe的readyState进行刷新。
至于php代码,本人不懂,无法做出解答。