at posts/single.html

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);
}

関連する日記