jQueryの Deferred
には、関数の非同期チェーンを実装するために使用できる2つの関数があります。
then()
deferred.then( doneCallbacks, failCallbacks ) Returns: Deferred
doneCallbacksDeferredが解決されたときに呼び出される関数または関数の配列。
failCallbacksDeferredが拒否されたときに呼び出される関数または関数の配列。
pipe()
deferred.pipe( [doneFilter] [, failFilter] ) Returns: Promise
doneFilterDeferredが解決されるときに呼び出されるオプションの関数。
failFilterDeferredが拒否されたときに呼び出されるオプションの関数。
then()
はpipe()
よりも少し長くなっているので、後者はいくつかの追加の利点を追加する必要がありますが、正確な違いは私を免れます。両者はほぼ同じコールバックパラメータを取りますが、名前が異なり、Deferred
を返すこととPromise
を返すことの違いはわずかです。
私は公式ドキュメントを何度も読みましたが、常に頭を包み込むにはあまりにも「密集」していることを見つけました。それぞれの長所と短所。
だから、いつthen
を使用したほうがよいのか、いつpipe
を使用したほうがよいのか?
Felixの優れた答え は、これら2つの機能の違いを明確にするのに非常に役立ちました。しかし、then()
の機能がpipe()
の機能よりも望ましい場合があるのだろうか。
pipe()
がthen()
よりも強力であることは明らかであり、前者は後者ができることなら何でもできるようです。 then()
を使用する理由の1つは、その名前が同じデータを処理する関数のチェーンの終了としての役割を反映しているためかもしれません。
しかし、then()
が元のDeferred
を返す必要があるユースケースはありますが、pipe()
ではできません。新しいPromise
?を返すためです
jQuery 1.8.then
は.pipe
と同じように動作するため:
廃止予定通知: jQuery 1.8では、
deferred.pipe()
メソッドは廃止されました。代わりにdeferred.then()
メソッドを使用する必要があります。
そして
jQuery 1.8以降、
deferred.then()
メソッドは、関数を介して遅延オブジェクトのステータスと値をフィルター処理できる新しいプロミスを返し、現在非推奨となっているdeferred.pipe()
メソッドを置き換えます。
以下の例は、一部の人にとってはまだ役に立つかもしれません。
それらは異なる目的に役立ちます:
.then()
は、プロセスの結果を処理する場合、つまり、ドキュメントにあるように、遅延オブジェクトが解決または拒否された場合に使用されます。 .done()
または.fail()
を使用するのと同じです。
.pipe()
を使用して、何らかの方法で結果を(pre)filterします。 .pipe()
へのコールバックの戻り値は、done
およびfail
コールバックへの引数として渡されます。また、別の遅延オブジェクトを返すことができ、この遅延オブジェクトに次のコールバックが登録されます。
.then()
(または.done()
、.fail()
)の場合はそうではありません。登録されたコールバックの戻り値は無視されます。
したがって、either.then()
or.pipe()
。あなたはcould.pipe()
を.then()
と同じ目的で使用しますが、逆は成り立ちません。
いくつかの操作の結果はオブジェクトの配列です:
[{value: 2}, {value: 4}, {value: 6}]
そして、値の最小値と最大値を計算します。 2つのdone
コールバックを使用すると仮定します。
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" */
});
明らかにこれは作り上げられた例であり、この問題を解決するための多くの異なる(おそらくより良い)方法がありますが、それがポイントを説明することを望みます。
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
});
});
}
遅延オブジェクトを使用して、makeCalls
を呼び出す他のコードがsecondAjax呼び出しのコールバックをアタッチできるようにしますが、
makeCalls().done(function() {
// this is executed after the first Ajax call
});
2番目の呼び出しはdone
コールバック内で行われ、外部からはアクセスできないため、望ましい効果はありません。
解決策は、代わりに.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コールにコールバックを追加できるようになりました。
一般的に、遅延オブジェクトはコードを分離する興味深い方法を提供します:)
then()
ではなくpipe()
を使用する必要がある場合はありません。 pipe()
が渡す値をいつでも無視することを選択できます。mightpipe
-しかし、問題になる可能性は低いです。
そのため、どちらの場合も常にpipe()
を常に使用できるように思えるかもしれません。 ただし、pipe()
を使用することにより、コードを読んでいる他の人(今から6か月後の自分を含む)に重要度を戻り値に。破棄する場合、このセマンティックコンストラクトに違反しています。
それは、決して使用されない値を返す関数を持っているようなものです:紛らわしい。
したがって、必要な場合はthen()
を使用し、必要な場合はpipe()
を使用してください...
実際、.then()
と.pipe()
の違いは不要とみなされており、jQueryバージョン1.8と同じになっています。
jaubourg
によるコメント jQueryのバグトラッカーで ticket#1101 "MAKE DEFERRED.THEN == DEFERRED.PIPE LIKE PROMISE/A":
1.8では、古いものを削除して現在のパイプに置き換えます。しかし、非常に悲しい結果は、非標準のdone、fail、progressを使用するように人々に伝える必要があることです。提案は単純で効率的ではなく、単にコールバックを追加することを意味します。
(エンファシス鉱山)