2010年2月9日火曜日

JSDeferredを誤解。

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
当たり前だけど、「chainのnextとそうでないnextは違う」ということです。debugを挿入して追ってみました。

prototypeのnext
  next  : function (fun) { 
    debug('Deferred.prototype.next');
    return this._post("ok", fun) 
  },

ブラウザ差異を吸収するためのモノのようなので、defaultのみをチェックする。
Deferred.next_default = function (fun) {
  debug('Deferred.next_default');
        var d = new Deferred();
        var id = setTimeout(function () { d.call() }, 0);
        d.canceller = function () { clearTimeout(id) };
        if (fun) d.callback.ok = fun;
        return d;
};

Deferred.next = Deferred.next_faster_way_readystatechange ||
                Deferred.next_faster_way_Image ||
                Deferred.next_default;

実行したテストコード
test('very simple tests for using jsdeferred with qunit.', function(){
  var x = 0;
  Deferred.define();
  next(function(){
    x = 2;
  })
  .next(function(){
    x = 1;
  })
  .next(function(){
    equals(x, 1);
    start();
  });
  stop(100);
});
これも当たり前だけど、グローバルに挿入されているinstanceのものが1回呼ばれた後、prototypeのほうが2回呼ばれます。設計意図を理解せねば。それからDeferred.prototype.fnとDeferred.fnの違いもわからないとだめだなぁ。var d = Deferred; d.fn()とDeferred.fn()は意味が違う。

2010年2月8日月曜日

まださまよっている。

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
x=2が行われた後、next()が積まれてx=1が実行され、そしてequals(x, 1)にいく。
test('bad use (3) of jsdeferred with qunit.', function(){
  var x = 0;
  Deferred.define();
  next(function(){
    x = 1;
  });
  equals(x, 0);
  x = 2;
  next(function(){
    equals(x, 1);
    start();
  });
  stop(100);
});

しかし、これはあまり自明じゃない。consoleにはpiyo hogeの順番で表示される。つまりstartが呼ばれてからx=1の代入が行われる。まったく好ましくない挙動。timerを消す必要があるかもしれない。
test('bad use (2) of jsdeferred with qunit.', function(){
  var x = 0;
  Deferred.define();
  next(function(){
    equals(x, 2);
    return next(function(){
      ok(true);
      x = 1;
      debug('hoge');
    });
  });
  equals(x, 0);
  x = 2;
  next(function(){
    equals(x, 2);
    debug('piyo');
    start();
  });
  stop(100);
});

QUnut + JSDeferred

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
  • Why it works?
  • Need to obtain Deferred instance for testing part from the target.

test('bad use (1) of jsdeferred with qunit.', function(){
  var x = 0;
  Deferred.define();
  next(function(){
    next(function(){ x = 1;
    });
  })
  .next(function(){
    equals(x, 0);
    start();
  });
  stop(100);
});

test('bad use (2) of jsdeferred with qunit.', function(){
  var x = 0;
  Deferred.define();
  next(function(){
    return next(function(){
      x = 1;
    });
  });
  next(function(){
    equals(x, 0);
    start();
  });
  stop(100);
});

test('right way: some thing bit complex using jsdeferred with qunit.', function(){
  var x = 0;
  var d = Deferred.define();

  d.next(function(){
    debug('first next ');
    return next(function(){
      debug('nested next');
      x = 1;
    });
  })
  .next(function(){
    debug('equals next ');
    equals(x, 1);
    start();
  });
  stop(100);
});