deferred.pipe()

参考: deferred.pipe() ? jQuery API

deferred.pipe( [doneFileter] [, failFilter] ) 返り値:Promise

概要

Deferred オブジェクトのコールバックへの引数をフィルタリングしたり、 Deferred で表されるタスクをチェーンしたりするユーティリティメソッド

用法

  • deferred.pipe( [doneFilter] [, failFilter] )

    • 1.6で追加
    doneFilter

    deferred が resolved の時に呼ばれる関数(オプション)

    failFilter

    deferred が rejected の時に呼ばれる関数(オプション)

  • deferred.pipe( [doneFilter] [, failFilter] [, progressFilter] )

    • 1.7で追加
    doneFilter

    deferred が resolved の時に呼ばれる関数(オプション)

    failFilter

    deferred が rejected の時に呼ばれる関数(オプション)

    progressFilter

    progress の通知が deferred に送られる時に呼ばれる関数(オプション)

詳細

※この記事はバージョン 1.8 の時点での記事です。1.9 では、 フィルタ関数・コールバックのコンテキスト(this)が Deferred オブジェクトから その Promise オブジェクトに変更されています。ご注意下さい。 (参考)

※jQuery 1.8 以降、deferred.pipe()の機能は deferred.then()にコピーされています。 おそらくdeferred.pipe()は 非推奨(Deprecated)になり、その代わりを deferred.then()が担うことになると思われます。

deferred.pipe()(deferred は Promise オブジェクト でも可)は関数オブジェクトを引数に取り、 Promise オブジェクトを返します。 コールバックに渡される引数をフィルタリングしたり、 タスクをチェーンすることができます。

フィルタリング

フィルタリングについては、コールバックを登録する前に あらかじめdeferred.pipe()でフィルタ関数を 登録することで実現できます。コールバックを登録した後の オブジェクトでpipe()を実行しても フィルタリングされません。 deferred.pipe()の返り値である Promise オブジェクトにコールバックを登録します。 pipe()を実行したオブジェクトにコールバックを 登録してもフィルタリングされません。 done、fail、progress コールバックの実行前に、 doneFilter (第一引数)、failFilter (第二引数)、 progressFilter(第三引数)(※1.7から) に渡したフィルタ関数が 呼び出されます。フィルタ関数を登録しない場合は nullを渡します。

// 下のコードはフィルタリングされない
// コールバックを登録する前に pipe を実行する必要がある
jQuery.Deferred().done(function(val){
  // 何らかの処理
}).pipe(function(val){
  return val * 2;
});

// 下のコードはフィルタリングされない
// コールバックは pipe() から返る Promise オブジェクトに
// 登録する必要がある
var defer = jQuery.Deferred();
defer.pipe(function(val){
  return val * 2;
});
defer.done(function(val){
  // 何らかの処理
})

// 下のコードはフィルタリングされる
var prom = jQuery.Deferred().pipe(null, function(val){
  return val * 2;
}).fail(function(val){
  // val にはフィルタリングされた値が入る
  // 何らかの処理
});

フィルタ関数にはコールバック関数に渡されるはずだった値が 渡されます。そして、フィルタ関数の返り値が Deferred や Promise オブジェクト以外なら その返り値が コールバック関数の第一引数に渡されます。 第二引数以降には渡されません。

var defer = jQuery.Deferred();
defer.pipe(function(arg1, arg2, arg3){
  return (arg1 + arg2 + arg3) * 2;
}).done(function( val ){
  // val == 120
});
defer.resovle(10, 20, 30);

pipe()を複数回実行すれば フィルタ関数を複数登録できます

// filter1, filter2 はフィルタ関数とする
var defer = jQuery.Deferred();
var filtered = defer.pipe( filter1 ).pipe( filter2 );
filtered.done(function( val ){
  // filter1 -> filter2 と実行される
  // filter2 には filter1 の返り値が渡される
  // val は filter2 の返り値が入る
});

フィルタ関数のコンテキスト(thisで参照する値)は、 元の Deferred オブジェクトがresolveWith()( rejectWith(), notifyWith())で指定していれば その指定した値になります(1.6.3 以降)。対して resolve()(reject(), notify()) が実行された場合は、そのフィルタ関数を引数として受け取った pipe()を実行した Deferred オブジェクトになります。 Promise オブジェクトからpipe()が 実行されていても、その Promise オブジェクトの生成元の Deferred オブジェクトになります。 pipe()は内部で作成した Deferred オブジェクトの Promise オブジェクトを返すため、その Promise オブジェクトに 登録したコールバックやフィルタ関数のコンテキストは、 pipe()の内部で作成した Deferred オブジェクト になることに注意して下さい。

// フィルタ関数のコンテキストを調べる
var defer = $.Deferred();
defer._defType = "defer1";

var filtered = defer.pipe(function( value ) {
  console.log(value); // → 5
  console.log(this);  // → _defType == "defer1"
  return value * 2;
});

filtered._defType = "filtered1";

filtered = filtered.pipe(function( value ) {
  console.log(value); // → 10
  console.log(this);  // → 上の pipe() 内部で作成された Deferred
  return value * 2;
});

filtered._defType = "filtered2";

filtered.done(function( value ) {
  console.log(value); // → 20
  console.log(this);  // → 2つ目の pipe() 内部で作成された Deferred
});

defer.resolve( 5 );

タスクの連結

フィルタ関数が Deferred (Promise) オブジェクトを返す場合、 pipe()が返す Promise オブジェクトに登録された コールバックは、フィルタ関数が返した Deferred オブジェクトの 状態に応じて呼び出されます。 これを利用して非同期なタスクの連結が行えます。

var defer = $.Deferred();
defer._defType = "original";
var defNum = 1;

var done = function( value ){
  console.log(defNum + "個目 doneFilter");
  console.log(this);
  console.log( value );
  // フィルタ関数内で次のタスクの Deferred オブジェクトを作成
  var nextDefer = $.Deferred();
  nextDefer._defType = "nextDefer" + defNum;
  // 非同期タスクを setTimeout で擬似的に表現
  setTimeout(function(){
    nextDefer.resolve( value * 2 ); // タスクが完了したら通知
  },  parseInt( (Math.random() + 1) * 1000 ));
  defNum++;
  return nextDefer; // Deferred オブジェクトを返すことで連結
};

// タスクが完了してから次の done が実行される
var filtered = defer.pipe( done ).pipe( done ).pipe( done );

// 連結したタスクを全て実行してから最後に実行される
filtered.done(function( value ) {
  console.log("doneCallback");
  console.log(this);
  console.log(value);
});

defer.resolve( 5 );

/*  ↓出力
1個目 doneFilter
Object { _defType="original", resolve=function(), ...}
5
2個目 doneFilter
Object { _defType="nextDefer1", resolve=function(), ...}
10
3個目 doneFilter
Object { _defType="nextDefer2", resolve=function(), ...}
20
doneCallback
Object { _defType="nextDefer3", resolve=function(), ...}
40
*/

フィルタ関数が Deferred (Promise) オブジェクトを返す場合、 pipe()が返す Promise オブジェクトに登録された コールバックへの引数は、フィルタ関数の返り値の Deferred オブジェクトから 実行されるメソッド(resolve(), reject()など) の引数が渡されます。 コールバックのコンテキストは、その実行の引き金になった Deferred オブジェクト、もしくは~With()で 指定した値になります。

スポンサードリンク