伝説のcomet(iframe版)?

25607 ワード

cometには、ロングポーリング(long-polling)とiframeストリーム(streaming)の2つの実装方法があります.
demoダウンロード:comet-iframe.zip
comet関連資料:http://www.ibm.com/developerworks/cn/web/wa-lo-comet/
前のエッセイでは長いポーリングのコードを書いていましたが、それが正しいかどうかは分かりませんが、普通のajaxのような感じがしますので、ここではiframeストリームの作り方を書いています.
フロントエンドコード:


View Code
<!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>

バックグラウンドコード:


View Code
<?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属性を1つの長い接続に対する要求に設定することで、サーバ側はクライアントにデータをどんどん入力することができる」とiframeのコンテンツから長時間の要求を行い、コンテンツを転送する必要がある場合に親ページjsメソッドを呼び出すことでページ表示を実現し、これによりcometに必要な効果を達成します.
iframeストリームを使用する不足の1つはIE、opera、chromeブラウザの下で、ずっとダウンロードが完了していないことを表示して、しかもマウスとブラウザの上のその輪はずっと回転して、IE 678の下で、googleの大牛たちは“html file”を使うことを通じてこの問題を解決して、IE 9は私が試して、“html file”を支持していないで、もちろんIE 9のあの輪はもう回転しません.しかしopera、chromeは「html file」をサポートせず、解決できません.
iframeのもう一つの問題はリクエストのタイムアウトであり、iframeがタイムアウトした場合、リフレッシュして接続を再確立する必要があると判断する必要があります.通常、iframeのonloadイベントをリフレッシュすることができ、iframe接続コンテンツがタイムアウトするとonloadイベントがトリガーされます.「htmlfile」ではiframeはonloadをサポートしていませんが、iframeのreadyStateを読み取ることができ、readyStateがcompleteの場合は要求タイムアウトを示すので、setIntervalでiframeのreadyStateを判断してリフレッシュすることができます.
phpコードについては、私にはわかりません.答えられません.