LoginSignup
32
33

More than 5 years have passed since last update.

Ajaxでの戻り値を処理するコールバック関数を動的に受け渡す

Posted at

経験則的に、たいていWebアプリを開発していて処理経路が煩雑化してしまう部分がAjax処理部分だ。直近の開発では、その部分をできる限り汎用化しようと思って、コールバック型のAjax処理を作ってみた。
建付けとしては、Ajaxの処理をクロージャ的に定義しておき、Ajaxの処理後に実行するコールバック関数名を引数で渡して、Ajax後の戻り値と合わせてコールバック関数を実行させるというものだ。色々と試行錯誤しながら実装できたので、備忘録として残しておく。

JavaScriptでのコールバック処理

まず、コールバック処理のメインとなるのが、「JavaScriptで関数名を文字列として動的に指定して、関数コールを行う」という部分だ。これにはいくつか方法があるが、下記の3つが使い勝手的に良い感じがした。

1. eval() を使う

// 関数名を変数として定義
var function_name = 'callbackFunction';
// 動的関数名の実行
eval(function_name + "();");

// コールバック関数の実体
function callbackFunction() {
  alert('Hello!');
}

2. Functionコンストラクタを使う。

// 関数名を変数として定義
var function_name = 'callbackFunction';
// 受け取った関数名を関数として実行するためのコンストラクタ
var Callback = new Function('return ' + function_name + '();');
// 動的関数名の実行
Callback();

// コールバック関数の実体
function callbackFunction() {
  alert('Hello!');
}

3. コールバック用のクラスを準備する。

// コールバック用のクラスを定義
var CallbackClass = function() {

  this.callbackMethod = function() {
    alert('Hello!');
  }

};
// クラスをインスタンス化
var Callback = new CallbackClass();

// 関数名を変数として定義
var function_name = 'callbackMethod';
// 動的関数名の実行
Callback[function_name]();

一番お手軽なのはやはり eval() を使う方法だ。
しかし、 jshint でJavaScriptの構文制御を行っていたりすると、デフォルトで設定値 evil が false になっているため、1. と 2. はエラーになってプリコンパイルが通らない。
.jshintrc"evil": true を設定して eval()new Function を許可してもいいのだが、JavaScriptのセキュリティポリシー的に安全性が失われてしまうのでそれはしたくなかった・・・。
──ということで、私の場合は 3. の一択しかなかった。まぁ、一番スマートな方法かもしれない。

Ajax処理のクロージャ

Ajax処理は結構カオスになりやすい部分なので、どんなAjaxでも汎用的に処理できるように、できる限りシンプルにして、再利用し易いように無名関数として定義しておく。
なお、Ajax処理はおなじみの jQuery である。

// jQueryのトップレベルスコープにAjaxレスポンスを格納するオブジェクトをあらかじめ準備しておく
$.ajaxResponse = {};

// 汎用Ajax処理
var CallAjax = function(){
  if (arguments.length < 2) {
    return false;
  }
  var ajax_url = arguments[0];
  var method = arguments[1];
  var post_data = typeof arguments[2] !== 'undefined' ? arguments[2] : null;
  var data_type = typeof arguments[3] !== 'undefined' ? arguments[3] : 'text';
  var callback_function = typeof arguments[4] !== 'undefined' ? arguments[4] : null;

  var jqXHR = $.ajax({
    async: true,
    url: ajax_url,
    type: method,
    data: post_data,
    dataType: data_type,
    cache: false,
    beforeSend: function(xhr, set) {
      // return;
    }
  });

  jqXHR.done(function(data, stat, xhr) {
    console.log({
      done: stat,
      data: data,
      xhr: xhr
    });
    if ('script' !== data_type) {
      $.ajaxResponse = { 'responseText': jqXHR.responseText, 'status': jqXHR.status, 'statusText': jqXHR.statusText };
    } else {
      return data;
    }
    if ('' !== callback_function) {
      return Callback[callback_function]();
    }
  });

  jqXHR.fail(function(xhr, stat, err) {
    console.log({
      fail: stat,
      error: err,
      xhr: xhr
    });
  });

  jqXHR.always(function(res1, stat, res2) {
    console.log({
      always: stat,
      res1: res1,
      res2: res2
    });
    if (stat === 'success') {
      alert('Ajax Finished!');
    }
  });

};

──で、Ajaxしたくなったら、

CallAjax( './ajax.php', 'post', { 'event': 'retrieve_html' }, 'html', 'render_html' );

──のように呼び出す次第。
例えば、上の呼び出し例では、Ajaxの処理実体である ajax.php をPOSTコールして、HTML形式の文字列を取得し、コールバック関数として render_html を呼び出すような建付けである。
Ajaxの通信後の受け処理としては、Ajaxの戻り値がJavaScriptのコマンドだった場合は、そのまま実行し、それ以外の場合は、 $.ajaxResponse オブジェクトに格納している。もし、コールバック関数名が指定されていた場合は、その後にコールバック関数を呼び出すという流れだ。

コールバッククラスによるAjax後のコールバック処理

コールバッククラスの定義例としては、下記のようになる。

// Callback処理用のクラス
var CallbackClass = function() {

  this.render_html = function(){

    $('body').append( $.ajaxResponse.responseText );

  };


};
var Callback = new CallbackClass();

クラス内の各メソッドがAjaxのコールバック関数になるという次第だ。例えば、 render_html メソッドではAjaxで受け取った HTML 文字列を <body> タグ内の末尾に追加するというjQuery処理を行っている。

あとはAjaxの戻り値に対して何か処理をしたい時に、このクラスに専用のメソッドを追加していくだけで、色んなケースのAjaxに対応できるようになる。

32
33
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
32
33