Deferred のメモ諸々

callback 関数が Deferred オブジェクトを戻した場合

Collection & Copy - Deferredチェーン、非同期処理の逐次実行

コールバック処理の中で、Deferredのインスタンスを返すと、元のDeferredはポーズされ(pausedがtrueになる)、返されたDeferredオブジェクトに自分への通知をセットして、処理の終了を待ちます。

Async.js 内の _fire 関数内で、戻り値が MochiKit.Async.Deferred だった場合の処理があった。
何に使えるかは、ちょっと置いといて、とりあえず試しに書いたコード。

var parent = partial(add_message, 'parent');
var child = partial(add_message, 'child');
var parent_make_child = compose(partial(make_child, child), parent);

var d = succeed('start');
d.addCallback(parent);
d.addCallback(parent);
d.addCallback(parent_make_child);
d.addCallback(parent);
d.addCallback(parent);
d.addCallback(parent_make_child);
d.addCallback(parent);
d.addCallback(parent);

function add_message (message, target) {
  target += ' ' + message;
  alert(target);
  return target;
}

function make_child (child, target) {
  var d = wait(10, target);
  d.addCallback(child);
  d.addCallback(child);
  return d;
}

へー。

DeferredList

複数の Deferred の callback を待つ Deferred の事。

例えば、下記のように、二つの Deferred オブジェクトが存在している場合・・・

var d1_callback = partial(increment, 'd1');
var d2_callback = partial(increment, 'd2');

var d1 = new Deferred();
d1.addCallback(d1_callback);
d1.addCallback(d1_callback);
d1.addCallback(d1_callback);

var d2 = new Deferred();
d2.addCallback(d2_callback);
d2.addCallback(d2_callback);
d2.addCallback(d2_callback);

function increment (msg, num) {
  print(msg + ' : ' + num);
  return num + 1;
}

下記のように、DeferredList オブジェクトを作る事で、d1 と d2 の二つが callback を受け取るまで待ってから、処理を行う事ができる。

var dl = new DeferredList([d1, d2], false, false, false);

dl.addCallback(partial(print_num, '<callback1>'));
dl.addCallback(partial(print_num, '<callback2>'));

function print_num (msg, results) {
  print(msg);
  map(
    function (result) {
      if (result[0] == true) {
        print('value = ' + result[1]);
      } else {
        print(result[1].message);
      }
    }, results
  );
  return results;
}

ここで、下記を実行すると・・・

d1.callback(0);
d2.callback(10);

下記の通り、出力される。

d1 : 0
d1 : 1
d1 : 2
d2 : 10
d2 : 11
d2 : 12
<callback1>
value = 3
value = 13
<callback2>
value = 3
value = 13

下記を実行すると・・・

d1.callback(0);
d2.errback('error!!');

下記の通り、出力される。

d1 : 0
d1 : 1
d1 : 2
<callback1>
value = 3
error!!
<callback2>
value = 3
error!!

第二引数に true を渡すと、管理している Deferred が一つでも callback を受け取ると処理を実行する。
例えば、下記のように DeferredList を作った場合・・・

var dl = new DeferredList([d1, d2], true, false, false);

dl.addCallback(partial(print_num, '<callback1>'));
dl.addCallback(partial(print_num, '<callback2>'));

function print_num (msg, results) {
  print(msg);
  print( 'index = ' + results[0]);
  print( 'value = ' + results[1]);
}

下記を実行すると・・・

d2.callback(10);

下記のように出力される。

d2 : 10
d2 : 11
d2 : 12
<callback1>
index = 1
value = 13
<callback2>
index = 1
value = 13

第三引数に true を渡すと、管理している Deferred が一つでも errback を受け取ると処理を実行する。
例えば、下記のように DeferredList を作った場合・・・

var dl = new DeferredList([d1, d2], false, true, false);
dl.addErrback(error);

function error (e) {
  print('message:' + e.message);
  return 0;
}

下記を実行すると・・・

d1.errback('error!!');

下記のように出力される。

message:error

第四引数に true を渡すと、管理している Deferred に DeferredList が追加する errback が null を返すようになる。
DeferredList は new された時に、第一引数に渡された Deferred オブジェクト一つ一つに、自分の callback や errback を呼ぶ _cbDeferred 関数を callback と errback として追加する。
その、_cbDeferred が、errback として実行された際、戻り値として null を返す・・・と言う事。
例えば、下記のように DeferredList を作った場合・・・

var dl = new DeferredList([d1, d2], false, false, true);

d1.addCallback(d1_callback);
d2.addCallback(d2_callback);

dl.addCallback(partial(print_num, 'callback0'));

下記を実行すると・・・

d1.callback(0);
d2.errback('error');

下記のように出力される。

d1 : 0
d1 : 1
d1 : 2
d1 : 3
<callback1>
value = 3
error!!
<callback2>
value = 3
error!!
d2 : null