98

jQueryDeferredには、関数の非同期チェーンを実装するために使用できる2つの関数があります。

then()

deferred.then( doneCallbacks, failCallbacks ) Returns: Deferred

doneCallbacksDeferredが解決されたときに呼び出される関数または関数の配列。
failCallbacksDeferredが拒否されたときに呼び出される関数または関数の配列。

pipe()

deferred.pipe( [doneFilter] [, failFilter] ) Returns: Promise

doneFilterDeferredが解決されたときに呼び出されるオプションの関数。
failFilterDeferredが拒否されたときに呼び出されるオプションの関数。

then()私はそれより少し長くなっていることを知っているpipe()ので、後者はいくつかの追加の利点を追加する必要がありますが、違いが正確に何であるかは私にはわかりません。Deferred名前は異なり、aを返すこととaを返すことの違いPromiseはわずかに見えますが、どちらもほぼ同じコールバックパラメータを取ります。

私は公式ドキュメントを何度も読んだことがありますが、常に「密度が高く」すぎて頭を包み込むことができず、検索するとどちらかの機能について多くの議論が見つかりましたが、違いを明確にするものは見つかりませんでしたそれぞれの長所と短所。

では、いつ使用するのが良いのかthen、いつ使用するのが良いのpipeか?


添加

フェリックスの優れた答えは、これら2つの機能の違いを明確にするのに本当に役立ちました。then()でも、の機能よりもの機能の方がいい時があるのではないでしょうかpipe()

それはpipe()より強力であることは明らかでありthen()、前者は後者ができることは何でもできるようです。使用する理由の1つthen()は、その名前が、同じデータを処理する一連の関数の終了としての役割を反映しているためである可能性があります。

しかし、新しいものを返すために実行できないthen()元のを返す必要があるユースケースはありますか?Deferredpipe()Promise

4

3 に答える 3

106

jQuery 1.8 .thenは次と同じように動作するため、次のように動作し.pipeます。

非推奨の通知: jQuery 1.8以降、このdeferred.pipe()メソッドは非推奨になりました。deferred.then()代わりに、これを置き換えるメソッドを使用する必要があります。

jQuery 1.8以降、このdeferred.then()メソッドは、関数を介して延期されたステータスと値をフィルタリングできる新しいpromiseを返し、現在は非推奨のdeferred.pipe()メソッドを置き換えます。

以下の例は、まだ一部の人に役立つ可能性があります。


それらは異なる目的を果たします:

  • .then()プロセスの結果を処理するときはいつでも、つまり、ドキュメントに記載されているように、延期されたオブジェクトが解決または拒否されたときに使用されます。.done()またはを使用するのと同じ.fail()です。

  • .pipe()なんらかの方法で結果を(事前に)フィルタリングするために使用します。コールバックの戻り値は、およびコールバック.pipe()への引数として渡されます。また、別の遅延オブジェクトを返すこともでき、次のコールバックがこの遅延オブジェクトに登録されます。donefail

    .then()(または.done()、 )の場合はそうではなく、.fail()登録されたコールバックの戻り値は無視されます。

したがって、または 使用するわけではありません。と同じ目的で使用できますが、その逆は成り立ちません。.then() .pipe().pipe().then()


例1

いくつかの操作の結果は、オブジェクトの配列です。

[{value: 2}, {value: 4}, {value: 6}]

そして、値の最小値と最大値を計算したいとします。done2つのコールバックを使用すると仮定しましょう。

deferred.then(function(result) {
    // result = [{value: 2}, {value: 4}, {value: 6}]

    var values = [];
    for(var i = 0, len = result.length; i < len; i++) {
        values.push(result[i].value);
    }
    var min = Math.min.apply(Math, values);

   /* do something with "min" */

}).then(function(result) {
    // result = [{value: 2}, {value: 4}, {value: 6}]

    var values = [];
    for(var i = 0, len = result.length; i < len; i++) {
        values.push(result[i].value);
    }
    var max = Math.max.apply(Math, values);

   /* do something with "max" */ 

});

どちらの場合も、リストを繰り返し処理して、各オブジェクトから値を抽出する必要があります。

両方のコールバックで個別にこれを行う必要がないように、事前に何らかの方法で値を抽出する方がよいのではないでしょうか。はい!そして、それは私たちが使用できるもの.pipe()です:

deferred.pipe(function(result) {
    // result = [{value: 2}, {value: 4}, {value: 6}]

    var values = [];
    for(var i = 0, len = result.length; i < len; i++) {
        values.push(result[i].value);
    }
    return values; // [2, 4, 6]

}).then(function(result) {
    // result = [2, 4, 6]

    var min = Math.min.apply(Math, result);

    /* do something with "min" */

}).then(function(result) {
    // result = [2, 4, 6]

    var max = Math.max.apply(Math, result);

    /* do something with "max" */

});

明らかにこれは作り上げられた例であり、この問題を解決するための多くの異なる(おそらくより良い)方法がありますが、それがポイントを説明することを願っています。


例2

Ajax呼び出しを検討してください。前の呼び出しが完了した後に1つのAjax呼び出しを開始したい場合があります。1つの方法は、doneコールバック内で2番目の呼び出しを行うことです。

$.ajax(...).done(function() {
    // executed after first Ajax
    $.ajax(...).done(function() {
        // executed after second call
    });
});

ここで、コードを分離して、これら2つのAjax呼び出しを関数内に配置するとします。

function makeCalls() {
    // here we return the return value of `$.ajax().done()`, which
    // is the same deferred object as returned by `$.ajax()` alone

    return $.ajax(...).done(function() {
        // executed after first call
        $.ajax(...).done(function() {
            // executed after second call
        });
    });
}

遅延オブジェクトを使用して、 2番目のAjax呼び出しmakeCallsのコールバックをアタッチするために呼び出す他のコードを許可したいが、

makeCalls().done(function() {
    // this is executed after the first Ajax call
});

done2番目の呼び出しはコールバック内で行われ、外部からアクセスできないため、望ましい効果は得られません。

.pipe()解決策は、代わりに使用することです。

function makeCalls() {
    // here we return the return value of `$.ajax().pipe()`, which is
    // a new deferred/promise object and connected to the one returned
    // by the callback passed to `pipe`

    return $.ajax(...).pipe(function() {
        // executed after first call
        return $.ajax(...).done(function() {
            // executed after second call
        });
    });
}

makeCalls().done(function() {
    // this is executed after the second Ajax call
});

を使用.pipe()することで、呼び出しの実際のフロー/順序を公開せずに、「内部」Ajax呼び出しにコールバックを追加できるようになりました。


一般に、遅延オブジェクトは、コードを分離するための興味深い方法を提供します:)

于 2012-03-07T12:06:54.257 に答える
7

then()を使用しなければならない場合はありませんpipe()pipe()渡される値を無視することをいつでも選択できます。使用するとパフォーマンスがわずかに低下する可能性pipeがありますが、問題になる可能性はほとんどありません。

pipe()したがって、どちらの場合も常に使用できるように思えるかもしれません。ただし、を使用するpipe()ことで、コードを読んでいる他の人(6か月後の自分を含む)に、戻り値が重要であることを伝えています。それを破棄している場合は、このセマンティック構造に違反しています。

これは、決して使用されない値を返す関数を持っているようなものです。混乱を招きます。

だから、あなたがすべきときthen()に、そしてあなたがすべきときに使用しpipe()てください...

于 2012-06-18T19:19:13.970 に答える
5

実際、との違いは不要であると見なさ.then().pipe()ており、jQueryバージョン1.8と同じになっています。

jQueryのバグトラッカーチケット#11010「MAKEDEFERRED.THEN == DEFERRED.PIPE LIKE PROMISE / A」のコメントjaubourgから:

1.8では、古いパイプを削除して、現在のパイプに置き換えます。しかし、非常に悲しい結果は、提案が単純で効率的な、単にコールバックを追加することを意味しないため、標準外の完了、失敗、進行を使用するように人々に指示する必要があるということです。

(強調鉱山)

于 2012-08-07T08:27:04.543 に答える