prototype.js で定期リロード
唐突に prototype.js の話。 使うのは1年ぶりかな。 チャットのように、定期的にリロードする仕組みを実現するために prototype.js の Ajax.PeriodicalUpdater を使ってみた。
Ajax.PeriodicalUpdater の基本
prototype.js では、定期的なリロードのために Ajax.PeriodicalUpdater というクラスが用意されている。 IT戦記のサンプルを参考にして、まずはフツーに使ってみる。
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> <html lang="ja"> <head> <title>Test</title> <script type="text/javascript" src="prototype.js"></script> <script type="text/javascript" src="chat1.js"></script> </head> <body> <div id="message">default</div> <div id="freq">0</div> <input type="button" id="action" value="start" onclick="main()"> <textarea id="debug" style="width: 100%; height: 50%"></textarea> </body> </html>
chat1.js
function main() { var updater = false; if(!updater){ updater = new Ajax.PeriodicalUpdater { success: 'message' }, 'chat1.text', { frequency: 2, decay: 1.5, onException : function(req, e){ $('debug').value = e.name + ': '+ e.message + '\n'; } } ); } }
success で指定している message の要素が、定期的に chat1.txt の内容 (HTML) に置き換えられる。 frequency は更新周期(2秒)。 decay は減衰率といって、 chat1.txt が更新されていなかった場合に、次の更新周期がだんだん遅くなっていくというもの。 2秒、2秒×1.5=3秒、3秒×1.5=4.5秒…といった具合に、「次の更新周期 = 更新周期 × 減衰率」で計算されている。 chat1.txt が更新されると、更新周期は元の値(2秒)に戻るようになってて便利。
JSON データを使って更新する
さっきの例だと、サーバ側で HTML を整形して、それをそのまま読み込む使い方になる。 昔作った Ajax のチャットも同じようなアプローチで考えていた。 サーバ側で HTML を作っておけば、 Ajax が使えないブラウザにも対応しやすいと思っていたから。
でも、最近だと JSON でデータをやり取りして、クライアント側で HTML に変換するやり方が多い。 そういう場合にも、 Ajax.PeriodicalUpdater が使えると便利。 定期リロードを自分で作ると、結構面倒なんだよね。
ってことで、 JSON データを使う例。
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> <html lang="ja"> <head> <title>Test</title> <script type="text/javascript" src="prototype.js"></script> <script type="text/javascript" src="chat2.js"></script> </head> <body> <div id="message">default</div> <div id="freq">0</div> <input type="button" id="action" value="start" onclick="main()"> <textarea id="debug" style="width: 100%; height: 50%"></textarea> </body> </html>
chat2.js
function main() { var updater = false; if(!updater){ updater = new Ajax.PeriodicalUpdater( '', 'chat2.json', { frequency: 2, decay: 1.5, onSuccess: function(req, json){ response = eval('(' + req.responseText + ')'); $('message').innerHTML = response.name; }, onException : function(req, e){ $('debug').value = e.name + ': '+ e.message + '\n'; } } ); } }
chat2.json
{"name": "<b>Mr. Smith</b>"}
Ajax.PeriodicalUpdater の第一引数を空文字列 '' とし、 onSuccess を使って手動で更新するのがポイント。 eval を使った json データの変換は、昔の日記を参考にした。 ちなみに、第一引数に空のオブジェクト {} を指定すると、 prototype.js の 1.4 では動いたけど、最新の 1.5_pre1 ではエラーになった。
json データの Content-Type を以下のようにすると Safari や Opera でも日本語が使えるらしい。手元に環境が無いから実験できないけど。
Content-Type: application/x-javascript; charset=utf-8
innerHTML を使わずに要素を増やしていく
もう Ajax.PeriodicalUpdater とは関係なくなっちゃうけど、チャットのように差分を増やしていく場合は innerHTML を使わずに要素を足していった方がいい場合もある。 ここでは、 Insertion を使って要素を足してみた。 ついでに、 script.aculo.us を使って
onSuccess: function(req, json){ json = eval('(' + req.responseText + ')'); new Insertion.Top('message', '<li>' + json.name + '</li>'); new Effect.Highlight(mes.firstChild); }