GAE や Google Closure Library などの話題を扱います。python 初心者です。

2010年2月28日日曜日

Closure Library - XhrManager (2) キャンセル処理

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
(前回)WEB開発メモ: Closure Library - XhrManager

XhrManager 検証続き。

処理をキャンセル(abort)してみる。前回のコードにキャンセルボタンを追加し、これを押した時に XhrIo通信をキャンセルさせる。

function cancel(e) {
  btn_start.setEnabled(true);
  btn_cancel.setEnabled(false);
  for (i=0; i < 20; i++) {
     xhrm_.abort(i);
  }
  alert('cancel');
}

abort() には IDを指定する必要がある。サンプルでは 0〜19 の値を割り当てていたので、ここでは安易に全部の IDで abortをかけてみた。実際には呼び出し側で処理中の ID を覚えておいて必要なものだけ abortするのがいいだろう。

サンプル実行
無事?キャンセルできた。キャンセル時もコールバック関数は呼び出されていることがわかる。またabortをかけられた XhrIo は  getStatus() を呼び出すと -1 を返しているのがわかる。

abortの第2引数は opt_force となっていて、これを true にするとコールバック関数は呼び出されなくなる。



abort(idopt_force)
Aborts the request associated with id.
Arguments:
id :
The id of the request to abort.
opt_force :
boolean=
If true, remove the id now so it can be reused. No events are fired and the callback is not called when forced.
やってみる。
function cancel(e) {
  btn_start.setEnabled(true);
  btn_cancel.setEnabled(false);
  for (i=0; i < 20; i++) {
     xhrm_.abort(i, ture);
  }
  alert('cancel');
}

確かに呼ばれなくなった(-1表示が無い)。

2010年2月27日土曜日

Closure Library - Delay と ConditionalDelay

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
goog.async.Delay

goog.async.Dealy を使うと一定時間後にある関数を呼び出すことができる。
Delay (Closure Library API Documentation - JavaScript)

<script>
goog.require('goog.dom');
goog.require('goog.async.Delay');
</script>

<script>
function output(msg) {
var console = goog.dom.$('console');
console.innerHTML = console.innerHTML + msg + "
";
}

var counter_ = 1;
var delay = new goog.async.Delay(
function() {
output("count: " + counter_++);
delay.start();
}, 1000);
delay.start();
</script>

呼び出された関数内でさらに start() を呼び出すと、一定間隔で繰り返し関数を呼ぶことができる。


goog.async.ConditionalDelay

こちらは条件付きの Delay が作れる。コールバック関数の戻り値が true になるまでは指定した時間間隔で関数が呼び出され続ける。
ConditionalDelay (Closure Library API Documentation - JavaScript)

戻り値に false を固定で返せば延々と一定間隔で呼び出され続けるが、タイムアウトを設定することもできる。一定間隔でリトライをかけるような通信処理などに使えそうだ。

onSuccess, onFailure に成功時、失敗時(タイムアウト)の処理を書くこともできる。

サンプル:
<script>
      goog.require('goog.dom');
      goog.require('goog.async.ConditionalDelay');
    </script>

    <script>
      function output(msg) {
        var console = goog.dom.$('console');
        console.innerHTML = console.innerHTML + msg + "<br/>";
      }

      var counter_ = 1;
      var delay = new goog.async.ConditionalDelay(
          function() {
              output("count: " + counter_++);
              return counter_ >= 10;;
          });
      delay.onSuccess = function() { alert('good job!');};
      delay.onFailure = function() { alert('timeout');};
      delay.start(1000, 5000);
    </script>

start( ) の第2引数はデフォルトで0。これは0秒を表していて1回実行後は必ずタイムアウトになる(1回だけ実行したい場合に使える)。タイムアウト無しにする場合は負の値を指定する。


以下はソースコードのコメントから引用。

* Example:
 *
 *  function deferred() {
 *     var succeeded = false;
 *     // ... custom code
 *     return succeeded;
 *  }
 *
 *  var deferredCall = new goog.async.ConditionalDelay(deferred);
 *  deferredCall.onSuccess = function() {
 *    alert('Success: The deferred function has been successfully executed.');
 *  }
 *  deferredCall.onFailure = function() {
 *    alert('Failure: Time limit exceeded.');
 *  }
 *
 *  // Call the deferred() every 100 msec until it returns true,
 *  // or 5 seconds pass.
 *  deferredCall.start(100, 5000);
 *
 *  // Stop the deferred function call (does nothing if it's not active).
 *  deferredCall.stop();

2010年2月26日金曜日

Closure Library - XhrManager

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
Closure Library には XMLHttpRequest のラッパーである XhrIo が用意されている。

Asynchronous XMLHttpRequests with XhrIo - Closure Library - Google Code

これを使うと簡単にサーバとの通信が行える。こんな感じ(Googleのページより引用)。

  goog.net.XhrIo.send(dataUrl, function(e) {
      var xhr = e.target;
      var obj = xhr.getResponseJson();
      log('Received Json data object with title property of "' +
          obj['title'] + '"');
      alert(obj['content']);
  });


この XhrIo を使って複数のリクエストを扱う用途で XhrIoPool と XhrManager が用意されている。
XhrIoPool (Closure Library API Documentation - JavaScript)
XhrManager (Closure Library API Documentation - JavaScript)

XhrIoPool はその名の通りで、複数の XhrIo のインスタンスをプールして使いまわす用途で使う。XhrManager はその XhrIoPool を内部に持っていて複数リクエストを簡単に扱えるようにしたもの。XhrIoPool を使って自前で実装する方法もあるが、特別問題が無い限りは XhrManager を使った方が楽(※XhrIoPool を使った場合、インスタンスの開放やイベントの管理などを自前でやらなければならない)。


今回はこの XhrManager を試してみた。コードはこんな感じ。

xhrio1.html
<script>goog.require('goog.net.XhrManager');
</script>
<script>
var xhrm_ = new goog.net.XhrManager();

function output(msg) {
var console = goog.dom.$('console');
console.innerHTML = console.innerHTML + msg + "<br/>";
}

function handleResponse(e) {
var xhr = e.target;
output(xhr.getStatus() + " : " + xhr.getResponseText());
}

function start(e) {
  for (i=0; i < 10; i++) {
      xhrm_.send(
          i,
          '/echo?name=' + i,
          'GET',
          null,
          {},
          1,
          handleResponse);
    output('send: ' + i);
  }
}

</script>

基本的には (1)XhrManagerのインスタンスを作り、(2) send()で送信するだけ。上のサンプルでは 10回 send を実行し、結果を画面に書き出している。

呼び出している /echo はこんな感じ ※GAEで動作。
import os, time
from google.appengine.ext import webapp
from google.appengine.ext.webapp import util
from google.appengine.ext.webapp import template

class MainHandler(webapp.RequestHandler):
  def get(self):
    self.response.out.write(self.request.get('name'))


def main():
  application = webapp.WSGIApplication(
    [('/echo', MainHandler),
                  ], debug=True)
  util.run_wsgi_app(application)


if __name__ == '__main__':
  main()

単純に name パラメータの内容を書き出すだけ。これを表示することで、何番目のリクエストが処理されているかがわかる。

実行するとこんな感じ。
XhrManager.send は通信結果を待たずに 10本連続して実行される(非同期)。画面上 send: 0, 1,.. と表示されているのがそう。その後、処理の終わったものから 200: 0 (ステータスコード:id)と表示されていく。処理は並行実行されて、送信順とは違った順番となっているのがわかる。

2010年2月1日月曜日

Closure Library - トグルボタン

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
トグルボタンとはボタンを1回押すと押したままの状態を保持し、もう一度押すともとに戻るボタンのこと。Closure Library では ui.ToggleButton が用意されている。サンプルを作ってみた。

サンプルでは2つのボタンを用意し、交互に押し状態が変わるようにしてみた。

toggle.html
goog.require('goog.dom');
  goog.require('goog.events');
  goog.require('goog.ui.ToggleButton');

goog.ui.ToggleButton を require しておく。


メインはこんな感じ。
<div id="toggle1" class="goog-toggle-button">Toggle1</div>
    <div id="toggle2" class="goog-toggle-button">Toggle2</div>

    <script>
      var btn1 = goog.ui.decorate(goog.dom.$('toggle1'));
      var btn2 = goog.ui.decorate(goog.dom.$('toggle2'));
      btn1.setDispatchTransitionEvents(goog.ui.Component.State.ALL, true);
      btn2.setDispatchTransitionEvents(goog.ui.Component.State.ALL, true);

      goog.events.listen(btn1, goog.ui.Component.EventType.ACTION,
        function(e) {
          btn2.setChecked(!e.target.isChecked());
        });
      goog.events.listen(btn2, goog.ui.Component.EventType.ACTION,
        function(e) {
          btn1.setChecked(!e.target.isChecked());
        });
      btn1.setChecked(true);
      btn2.setChecked(false);
    </script>

書き方は通常のボタンと同じだが setDispatchTransitionEvents( ) がミソ(のようだ)。それぞれのボタンのイベントに相互の状態(setChecked)を変えるコードを書いて見た目を切り替えている。



下記リンクからサンプルが見られる。
http://closuresample.appspot.com/html/toggle.html