JSDeferred に引数束縛の bind, curry を追加 / Google Chrome の JSDeferred のインテグレーションを書いた
JSDeferred に引数束縛の bind, curry を追加 / Google Chrome の JSDeferred のインテグレーションを書いた
JSDeferred を使い始めて、Deferred チェインが便利なのは良いんだけど、そうすると既存の callback を引数にとる関数をうまく Deferred でラップしたくなってくる。ので callback 引数をよしなに next チェインへと引数束縛する Deferred.bind と、第一引数を callback として curry化する関数、Deferred.curry を作った。現在 bind ブランチに push して、cho45 せんせーのOKが出たら本家に取り込まれる予定。master に取り込まれまんた
たとえば、こんな引数をとる関数があったとする。
var myFunc = function(arg1, arg2, callback) {...};
この場合、三番目の引数が束縛され、Deferred の next チェインへと繋げられると嬉しい。そんなときは Deferred.bind を使う。
master 最新では、Deferrerd.bind という名称ではなく、Deferrerd.connect に変更になしました。また、Deferrerd.curry は無くなりました。
var myFuncD = Deferred.bind(myFunc,
null, /* 関数の this となるオブジェクト */
2, /* callback 関数の引数の場所 */
null /* errorback 関数の引数の場所。指定しなくても OK */
);
myFuncD(arg1, arg2).next(function(result) { /* callback */ });
な風に利用できる。なお bind/curry で作られた関数が返す Deferred の next は書き換えられており、通常の JSDeferred では next コールバックの引数は結果、もしくは結果の配列になるが、bind などの場合は通常のコールバックに渡る引数となる。(JSDeferred を使ってない人には解りにくい説明…)。実際の test でこんな感じ。
var f = function(arg1, arg2, callback) {
setTimeout(function() {
callback(arg1, arg2);
}, 10);
}
var fd = Deferred.bind(f, null, 2);
return fd(2,3).next(function(r0, r1) {
expect('bind f', 2, r0);
expect('bind f', 3, r1);
});
というわけで、callback を引数とする関数なら何でも Deferred 化できるようになった。
Google Chrome Extentions の API を Deferred 化するライブラリ
実用的な例で Google Chrome の API (window/tab/bookmark 操作のほとんどが callback を引数にとる) の JSDeferred のインテグレーションを書いてみた。
これを使うと bookmarks api を使った検索が
Deferred.chrome.bookmarks.search('Google').next(function(r) {
console.log(r); // BookmarkTreeNode
});
や、tab で開く操作が
Deferred.chrome.tabs.create({url: 'http://www.google.com/'}).next(function(tab) {
console.log(tab); // Tab instance
});
のように、Deferred チェインに沿った書き方で書けるようになる。