A Day in the Life

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 チェインに沿った書き方で書けるようになる。

記事の一覧 >