Deferred、Promise、Future の違いは何ですか?
これら 3 つすべての背後にある一般的に承認された理論はありますか?
5 に答える
選択された回答を含むこれらの回答は、約束を概念的に導入するのに適していますが、それらを実装するライブラリを使用するときに発生する用語の違いが正確に何であるかの詳細が欠けています (そして 重要な違いがあります)。
これはまだ進化中の仕様であるため、現在の答えは、参照 ( wikipediaなど) と実装 ( jQueryなど) の両方を調査しようとすることから得られます。
Deferred : 一般的な参考文献 1 2 3 4には記載されていません が、一般的に実装によって promise 解決のアービターとして使用されます (実装および)。 5 6 7
resolve
reject
deferred が promise である場合 ( を実装する)
then
も あれば、解決のみが可能な Deferred を持つ方がより純粋であり、ユーザーが を使用するために promise にアクセスすることを強制する場合もあります。 7then
Promise : 議論中の戦略を最も包括的に表す言葉。
シンクロニシティを抽象化したいターゲット関数の結果を格納し、
then
さらに別のターゲット関数を受け入れて新しい promise を返す関数を公開するプロキシ オブジェクト。 2CommonJSの例:
> asyncComputeTheAnswerToEverything() .then(addTwo) .then(printResult); 44
Future : いくつかの一般的な参考文献1 および少なくとも 1 つの一般的な実装 8で見られる一見非推奨の用語ですが 、「約束」という用語に優先して議論から段階的に廃止されているように見えます 3 。 9
ただし、少なくとも 1 つのライブラリでは、同期性とエラー処理を抽象化するために一般的にこの用語を使用していますが、
then
機能は提供していません。 10 「約束」という用語を避けることが意図的であったかどうかは不明ですが、約束は「thenables」を中心に構築されているため、おそらく良い選択です。 2
参考文献
- ウィキペディアの約束と先物
- プロミス/A+仕様
- Promise の DOM 標準
- DOM 標準約束仕様 WIP
- DOJO ツールキット Deferred
- jQuery Deferred
- Q
- FutureJS
- Promise の Functional Javascript セクション
- AngularJS 統合テストの先物
その他、混乱を招きかねないもの
-
(TL;DR、Promises/A+ は主に Promises/A のあいまいさを解決します)
OPの質問に私が答えようとした方法に対する明らかな嫌悪感に照らして。文字通りの答えは、promise は他のオブジェクトと共有されるものであり、deferred は非公開にする必要があるということです。主に、遅延 (通常は Promise を拡張する) はそれ自体を解決できますが、Promise は解決できない場合があります。
詳細に興味がある場合は、Promises/A+を調べてください。
私の知る限り、包括的な目的は、標準化されたインターフェースを介して明確さを改善し、結合を緩めることです。@jfriend00 からの提案された読み物を参照してください。
コールバックを関数に直接渡すのではなく、緊密に結合されたインターフェイスにつながる可能性がありますが、promise を使用すると、同期または非同期のコードの懸念を分離できます。
個人的には、deferred が特に役立つのは、たとえば、非同期リクエストによって生成されるテンプレートを処理する場合、依存関係のネットワークを持つスクリプトをロードする場合、ユーザー フィードバックをフォーム データにブロックしない方法で提供する場合です。
実際、CodeMirror を JS モードで非同期にロードした後に何かを行う純粋なコールバック形式を比較してください (申し訳ありませんが、しばらくの間 jQuery を使用していません)。
/* assume getScript has signature like: function (path, callback, context)
and listens to onload && onreadystatechange */
$(function () {
getScript('path/to/CodeMirror', getJSMode);
// onreadystate is not reliable for callback args.
function getJSMode() {
getScript('path/to/CodeMirror/mode/javascript/javascript.js',
ourAwesomeScript);
};
function ourAwesomeScript() {
console.log("CodeMirror is awesome, but I'm too impatient.");
};
});
約束の定式化されたバージョンに(繰り返しますが、申し訳ありませんが、私はjQueryについて最新ではありません):
/* Assume getScript returns a promise object */
$(function () {
$.when(
getScript('path/to/CodeMirror'),
getScript('path/to/CodeMirror/mode/javascript/javascript.js')
).then(function () {
console.log("CodeMirror is awesome, but I'm too impatient.");
});
});
半疑似コードで申し訳ありませんが、核となるアイデアがある程度明確になることを願っています。基本的に、標準化された promise を返すことにより、promise を渡すことができるため、より明確なグループ化が可能になります。
私にとって本当にすべてのクリックをもたらしたのは、 DomenicDenicolaによるこのプレゼンテーションでした。
githubの要点で、彼は私が最も好きな説明をしました、それは非常に簡潔です:
約束のポイントは、非同期の世界で機能的な構成とエラーバブリングを返すことです。
言い換えると、promiseは、同期の場合とほぼ同じくらい簡単に記述できる非同期コードを記述できるようにする方法です。
この例を考えてみましょう。
getTweetsFor("domenic") // promise-returning async function
.then(function (tweets) {
var shortUrls = parseTweetsForUrls(tweets);
var mostRecentShortUrl = shortUrls[0];
return expandUrlUsingTwitterApi(mostRecentShortUrl); // promise-returning async function
})
.then(doHttpRequest) // promise-returning async function
.then(
function (responseBody) {
console.log("Most recent link text:", responseBody);
},
function (error) {
console.error("Error with the twitterverse:", error);
}
);
これは、次の同期コードを記述しているかのように機能します。
try {
var tweets = getTweetsFor("domenic"); // blocking
var shortUrls = parseTweetsForUrls(tweets);
var mostRecentShortUrl = shortUrls[0];
var responseBody = doHttpRequest(expandUrlUsingTwitterApi(mostRecentShortUrl)); // blocking x 2
console.log("Most recent link text:", responseBody);
} catch (error) {
console.error("Error with the twitterverse: ", error);
}
(それでも複雑に聞こえる場合は、そのプレゼンテーションをご覧ください!)
延期に関しては、それは約束する方法.resolve()
です。Promises / B.reject()
仕様では、と呼ばれます。jQueryでは、それはです。.defer()
$.Deferred()
私の知る限り、少なくともjQuery 1.8.2の時点では、jQueryでのPromiseの実装は壊れていることに注意してください(その要点を参照)。Promises / A thenables
を
実装していると思われますが、「非同期try / catch」機能全体が機能しないという意味で、正しいエラー処理が得られません。非同期コードで「try/catch」を実行するのは非常にクールなので、これは残念です。
Promisesを使用する場合(独自のコードで試してみる必要があります!)、KrisKowalのQを使用してください。jQueryバージョンは、よりクリーンなjQueryコードを作成するためのコールバックアグリゲーターにすぎませんが、要点を見逃しています。
Futureに関しては、私にはわかりません。どのAPIでもそれを見たことがありません。
編集:以下の @Farmのコメントからの約束に関するDomenicDenicolaのyoutubeトーク。
ビデオからのマイケルジャクソン(はい、マイケルジャクソン)からの引用:
このフレーズを頭に入れてほしい: promiseは非同期値です。
これは優れた説明です。promiseは将来の変数のようなものです。ある時点で存在する(または発生する)何かへのファーストクラスの参照です。
Promiseは、Promiseの作成時に必ずしも知られていない値のプロキシを表します。これにより、ハンドラーを非同期アクションの最終的な成功値または失敗理由に関連付けることができます。これにより、非同期メソッドは同期メソッドのように値を返すことができます。非同期メソッドは、最終値の代わりに、将来のある時点で値を持つという promise を返します。
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
このdeferred.promise()
メソッドにより、非同期関数は、他のコードがその内部要求の進行状況またはステータスに干渉するのを防ぐことができます。Promise は、追加のハンドラーをアタッチするか、状態を判断するために必要な Deferred メソッド ( then、done、fail、always、pipe、progress、state および promise ) のみを公開しますが、状態を変更するメソッド ( resolve、reject、notify、resolveWith、 rejectWith、および notifyWith )。
ターゲットが指定さdeferred.promise()
れている場合、メソッドをそれにアタッチしてから、新しいオブジェクトを作成するのではなく、このオブジェクトを返します。これは、Promise 動作を既存のオブジェクトにアタッチするのに役立ちます。
Deferred を作成している場合は、Deferred への参照を保持して、ある時点で解決または拒否できるようにします。deferred.promise() を介して Promise オブジェクトのみを返すので、他のコードはコールバックを登録したり、現在の状態を検査したりできます。
簡単に言うと、Promiseはまだわかっていない値を表し、Deferredはまだ完了していない作業を表します。