LoginSignup
12
14

More than 5 years have passed since last update.

Javascript で複数のコールバックをまとめて受け取る

Posted at

以下のように「複数のコールバック呼び出しが完了した時点で処理をすすめる」パターンを簡素に書くことができます。
各コールバックに渡された引数もまとめて最後の then 関数に渡され、しかもその順番は cb.here を呼び出した順番と対応することが保証されます。(コールバックが呼び出された順ではありません)
これで複数リソースの読み込みも怖くない!

example.js
var cb = new Callback();
request(..., cb.here());
request(..., cb.here());
request(..., cb.here());
cb.then = function(result1, result2, result3) {

}
callback.js
var Callback = (function () {

  /**
   * 複数のコールバックをまとめて一つのコールバックにします。
   * @constructor
   * @example
   * var cb = new Callback();
   * asyncFunc1(..., cb.here()); // f('guitar') とコールバックされる
   * asyncFunc2(..., cb.here()); // f('fiddle','banjo') とコールバックされる
   * asyncFunc3(..., cb.here()); // f()  とコールバックされる
   * asyncFunc4(..., cb.here([])); // f('mandolin') とコールバックされる
   * cb.then = function(a, b, c, d) {
   *   // cb.here() を呼んだ数だけ引数が渡る
   *   // a は 'guitar'
   *   // b は ['fiddle', 'banjo']
   *   // c は null
   *   // d は ['mandolin']
   * }
   */
  var Callback = function() {
    this.resultList = [];
    this.stepCount = 0;
    this.callCount = 0;
    /**
     * すべてのコールバックをまとめて最終的に呼び出される関数。
     */
    this.then = null;
  };

  /**
   * コールバック関数を生成して返す。
   * 生成した関数が空引数で呼ばれた場合は null を。
   * 1引数で呼ばれた場合はその値を。
   * 2引数以上で呼ばれた場合は配列を登録し、
   * すべてのコールバックが呼び出された時点で
   * 登録した引数を then に渡して呼び出す。
   * here に空配列を渡した場合は引数の数にかかわらず配列を登録する。
   * @return {function(...)}
   */
  Callback.prototype.here = function() {
    var registerArray = arguments.length == 1 &&
        arguments[0] instanceof Array &&
        arguments[0].length == 0;
    if (arguments.length != 0 && !registerArray) throw new Error(
        "Callback#here に引数が渡されました。" +
        "xx.here() と書くべき場所で xx.here としている可能性があります。");
    return (function(callback, stepCount) {
      return function() {
        var result = arguments;
        if (!registerArray && result.length == 0) {
          callback.resultList[stepCount] = null;
        } else if (!registerArray && result.length == 1) {
          callback.resultList[stepCount] = result[0];
        } else {
          callback.resultList[stepCount] = [];
          for (var i = 0; i<result.length; i++) {
            callback.resultList[stepCount][i] = result[i];
          }
        }
        if (++callback.callCount >= callback.stepCount) {
          if (callback.then != null) {
            callback.then.apply(null, callback.resultList);
            Callback.call(this);
          } else throw new Error("then が未登録です");
        }
      }
    })(this, this.stepCount++);
  };

  return Callback;
})();
12
14
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
12
14