Javascript で複数のコールバックをまとめて受け取る
複数のコールバックをまとめて受け取るためのクラスを書いてみました。
JavaScript は何かとコールバックが多用される言語です。単発のコールバックならば問題はありませんが、複数のコールバックを同時に使用して、それらが全て呼ばれたときに処理を進めるなどの処理は記述が複雑になりがちです。
そこでこの Callback クラス。
var cb = new Callback(); request(..., cb.here()); request(..., cb.here()); request(..., cb.here()); cb.then = function(result1, result2, result3) { }
上記のように「複数のコールバック呼び出しが完了した時点で処理をすすめる」パターンを簡素に書くことができます。
各コールバックに渡された引数もまとめて最後の then 関数に渡され、しかもその順番は cb.here を呼び出した順番と対応することが保証されます。(コールバックが呼び出された順ではありません)
これで複数リソースの読み込みも怖くない!
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; })();
コードはご自由にお使いください。