PHPでComet:フォーカスの当たっていないウィンドウが更新されない

シェアする

  • このエントリーをはてなブックマークに追加
  • Evernoteに保存Evernoteに保存

PHPとprototype.jsを使ってAjaxでCometなチャットを作ろうとした。

FireFoxで動作検証していたのだが、ブラウザの複数ウィンドウを立ち上げ、別マシンでもウィンドウを立ち上げて検証していたところ、フォーカスの当たっていない(アクティブでない)ウィンドウでは、TextAreaが更新されないことに気づいた。

結論

更新する直前に"$(targetID).focus();"でフォーカスを当ててあげる。

<script>
//要prototype.js
function fAjaxUpdate(){
var sUrl      = './upload.php';
var sPars     = Form.serialize("idFormInput");
$('idTextArea').focus(); //←ここ ここ ここ
var oAjax = new Ajax.Updater(
"idTextArea",
sUrl,
{
method: 'post',
parameters: sPars,
});
}
</script>
Cometの仕組み

チャットなど、タイマーで定期的にリクエストして更新する通信アプリ、つまりPULL式(データを引っ張ってくるタイプ)のアプリの場合、更新時間が来るまで待つ必要がありタイムライグが発生するため、即時反応という体感がいまいちありません。(このクライアントからサーバーに定期的にリクエストを送信する方法をポーリングとも言います)

CometとはPUSH式、つまりサーバ側がクライアント側にデータを届ける仕組みを、アイデアと工夫で「擬似的にPUSH式を実装する仕組み」です。

イメージとしては、メーラーがメールを一定置きにチェックしに行く(PULL式である)のに対し、携帯のショートメールなどのようにサーバーからメールが送られてくるタイプ(PUSH式)との違いみたいなものです。

一般的なWEBの仕組みとして、サーバは、クライアント(ブラウザやJavascriptなど)がアクセスしてきた場合、リクエストされたWEBページ・スクリプト・画像・データなどを表示して終了します。(プル式。クライアントが情報を引き出すタイプ)

しかし、クライアントがアクセスしてきても即座に表示せず、サーバ側で変更があるまで掴んだまま離さない・反応しない、つまり即座にリクエスト結果を返さないのがCometの大きな特徴です。

当然サーバは反応しないので、しばらく経つとクライアント側はタイム・アウトでセッションを切るのですが、クライアントのJavascriptが即座に接続を繰り返すことで、サーバ側のリアルタイムな変更を得ることができるので、あたかもサーバから配信された(プッシュされた)ように見えるわけです。

これが擬似的なプッシュ式と言われるゆえんです。

経緯

海外やネットカフェにいてもオンラインでPHP、CSS、Javascript、HTMLソースをメンテナンスできる、いちいち保存したりアップロードしなくても紙copiのように即時更新されるオンライン・テキストエディタなるものが欲しかった。

となると、FormのTextAreaを”onClick()”とか”onKeyDown()”で更新できたらいいじゃんと思って、ググッてみたら”Nob Funaki”さんが作られたmemooという、まさにドンピシャなのがあった。

が、FireFox非対応とのこと。

OperaやSafariでの作業もあるため、ここはひとつ車輪の再発明かもしれないが、ブラウザ互換といえば、”prototype.js“!
いや、”jQuery“とかもあるんだけど…。

で、作ってみて、サーバ負荷を減らすためにキー押下処理ごとにリクエストしないようバッファ処理したりとか、色んな処理に悩まされながら、なんとかできたんです。(セキュリティ処理したら公開したいな。)

一人で作業する分には超便利なんですが、複数人作業だと更新のタイミング確認が面倒なこと面倒なこと。

やはりここはメンバーとSkypeで話しながら仲良くペア・プログラミングとかクールにやってみたいのが、合理の非合理というもの。

となると、一昔のチャットの悩みと同じで、METARefreshなAjaxで困った時のcometさん。

とはいえ、cometの実績はなし。そこで、実装の前にテストをしたい。上記のCometの仕組みだけだと問題もあるんだけど、まずはこんなところからはじめた。

すると上記現象が発生したんですよ。

アクティブなウィンドウで一生懸命更新しているのに、昔のデータ(更新されない非アクティブなウィンドウのデータ)がちょくちょく送られてきて、いささかイラッとくる。

「実際の利用時には複数ウィンドウなんて立ち上げないから」と割り切ってしまえば、そこまで気にしなくてもいいのかも、とも思ったが検証中はやはり複数ウィンドウを立ち上げるので、やはり現象がイラッとくる。

最初は、非アクティブなウィンドウがサーバからレスポンスが返ってきた際に、ウィンドウを前面に持ってくるなり、アクティブ化させるのかとも思ったが、それだと作業中のウィンドウのフォーカスを持っていかれて、ウィンドウ同士が必死にアクティブ化のピンポンをはじめるのは必死で、またイラッとしそうだったので、どうしようかと悩んだ。

ん?もしかして、フォーム(TextArea)にフォーカスを当てればいいとか?

で、Ajax.Updater()がレスポンスをエレメントのinnerHTMLに書き込む前にフォーカスを当ててみたら動いた。

あちょんぶりけ

とりあえず、このイライラを記録に残したかったの。

関連記事

「T_ENCAPSED_AND_WHITESPACE」エラー時に注意すべき点... 「T_ENCAPSED_AND_WHITESPACE」の原因がわからない よくある原因 ヒアドキュメントの宣言"<<<"の前にスペースが入っていなかった! ヒアドキュメント内に配列を使ってて"{}"でくくることを忘れてた! 括弧を閉じ忘れてた!(だいたい...
IEで「エラー:識別子、文字列または数がありません。」エラー... InternetExplorerで「エラー:識別子、文字列または数がありません。」エラーがにっちもさっちも Prototype.jsを使ってフォームをAjaxちっくに投稿するページを作っていたんですが、FireFoxとかは問題ないのにIEだと「実行しましたがページでエラーが発生しました。」とエ...
Geeklogの管理画面で記事一覧に列を追加する... Geeklogで記事一覧に任意の列を追加する方法 わたくし、Geeklogの記事管理画面(story.php)で記事一覧を表示する際に、編集アイコン列の隣に新しい列を挿入したかったんです。 結論 story.phpで列の定義を行い、lib-admin.phpで各行の処理を定義する。 ...
私のGeeklogのMVC的使い方(WebAPI化) GeeklogをWEBサービス的にAPI化する 2013/09/11 追記:5年半前の記事ですっかり放置していたのですが、なんと恐れ多くもGeeklogのivyweさんからコメントをいただきました。m(_ _;)m ガクガクブルブル すっかりKEINOSはGeeklog離れしていたのですが、...

スポンサーリンク
レクタングル(大)広告

シェアする

  • このエントリーをはてなブックマークに追加
  • Evernoteに保存Evernoteに保存
スポンサーリンク
レクタングル(大)広告