JavaScriptのDeferred、Promise、Futureの違いは何ですか?


300

Deferred、Promise、Futureの違いは何ですか?
これら3つすべての背後にある一般的に承認された理論はありますか?


11
これはjQueryとは関係がないと思います...
BoltClock

11
これを読む価値がある:msdn.microsoft.com/en-us/scriptjunkie/gg723713
jfriend00

8
私はそれらを自分で使用したことはありませんが、ウィキペディアen.wikipedia.org/wiki/Futures_and_promisesのかなり良い紹介があります。私はユースケースを完全に理解していませんが。javascriptのような非同期イベント駆動型言語。一見、コールバックで何が提供されているのか、おそらくよりクリーンなAPIを除いてわかりません。誰かが使用例を提供でき、これらの概念がどのように適用され、コールバックが非効率的なソリューションになる理由を示すことができれば、私はそれを気に入っています。@duriこれはjQueryとは関係ありません。jQueryタグを削除できますか
AshHeskes '24

2
@ jfriend00の素晴らしいリンク。おそらく回答に組み込む必要があります。
fncomp

@ jfriend00新しいリンク- msdn.microsoft.com/en-us/magazine/gg723713.aspx
C69

回答:


97

OPの質問にどのように答えようとしたかに対する明らかな嫌悪感に照らして。文字通りの答えは、プロミスは他のオブジェクトと共有されるものであり、遅延オブジェクトは非公開にする必要があるということです。主に、遅延(通常はPromiseを拡張する)はそれ自体を解決できますが、Promiseは解決できない場合があります。

マニューシャに興味がある場合は、Promises / A +を調べてください。


私の知る限りでは、包括的な目的は、明確化を改善し、標準化されたインターフェースを介して結合を緩めることです。@ jfriend00からの推奨読書を参照してください。

コールバックを関数に直接渡すのではなく、密接に結合されたインターフェイスにつながる可能性があるものをプロミスを使用すると、同期または非同期のコードに対する懸念を分離できます。

個人的には、遅延リクエストは、非同期リクエストによって入力されたテンプレート、依存関係のネットワークを持つスクリプトの読み込み、非ブロック的な方法でデータを形成するためのユーザーフィードバックを提供する場合などに特に役立ちます。

確かに、JSモードで非同期にCodeMirrorをロードした後に何かを行う純粋なコールバック形式を比較してください(申し訳ありませんが、しばらくの間 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.");
   };
});

promisesの公式化されたバージョンに対して(ここでも、申し訳ありませんが、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.");
   });
});

準疑似コードについてはお詫びしますが、コアとなるアイデアが多少明確になることを願っています。基本的に、標準化されたプロミスを返すことで、プロミスを渡すことができ、より明確なグループ化が可能になります。


10
この回答は役立つかもしれませんが、実際には質問に対応していません。いわゆる据え置きは、実装に応じて先物または約束のいずれかです。
awdz9nld

@MartinKällmanその通りです!私はしばらくこれを再訪せず、少し学びました。以下に別の回答を掲載しますが、使用例から利益を得ているようですので、そのままにしておいてください。
fncomp

@MartinKällman、新しい回答を書くことを検討。しかし、私はOPが実際に約束と延期が何であるかを知りたかったと思います。彼の実際の質問に対する答えは、大まかに言って、「据え置き者は自分で解決できる。AFAIK、約束と据え置きの背後にある理論は、コールバックを平坦化する手法である[Functional Reactive Programming | haskell.org/haskellwiki/Functional_Reactive_Programming]から来ている。」
fncomp 2013

2
これは完全に間違っており、あなたの例はコールバックを使うのと同じくらい簡単です。約束はコールバックの集約と分離についてではありませんが、同期コードが書かれるように非同期コードを書くためにDSLを提供します。特にfn(callback, errback)、密結合や有用性の低下はありませんfn().then(callback, errback)が、それでもプロミスを使用するには間違った方法です。カーゴカルトの$.when例は特に嫌いです- $.whenコールバックで機能する関数を使用できない理由はまったくありません。
エサイリヤ2013年

これは、コールバック地獄が何であるかを知ることができるという+1の質問には答えません。
Bhojendra Rauniyar

146

選択された回答を含むこれらの回答は、概念的にPromiseを導入するのに適していますが、Promiseを実装するライブラリを使用するときに発生する用語に正確にどのような違いがあるかについての詳細はありません(重要な違いがあり ます)。

それはまだ発展中の仕様なので、答えは現在(wikipediaのような)参照と実装(jQueryのような)の両方を調査しようとすることから来ています:

  • 据え置き: 一般的なリファレンスでは説明されていませんが、 1 2 3 4ですが、プロミス解決のアービターとして実装によって一般的に使用されています(実装および)。 5 6 7 resolvereject

    時々のDeferredも約束(実装されているthen)、 5 6 解像度の繰延ことができるだけを持っているために、より純粋と見られ、および使用するための約束をアクセスするためにユーザーを強制的に相手の回。 7 then

  • 約束:議論中の戦略の最も包括的な用語。

    シンクロニシティを抽象化するターゲット関数の結果を格納するプロキシオブジェクト。さらに、then別のターゲット関数を受け入れて新しいプロミスを返す関数を公開します。 2

    CommonJSの例:

    > asyncComputeTheAnswerToEverything()
        .then(addTwo)
        .then(printResult);
    44

     

    責任の解決が当てはまる人物については指定されていませんが、常に人気のある参考文献に記載されています。 1 2 3 4

    常に人気のある実装に存在し、解決能力は与えられません。 5 6 7

  • 将来:一部の人気のある参考文献1 と少なくとも1つの人気のある実装 8に見られる廃止予定の用語ですが、 「約束」3という用語が優先され、議論から除外 されているようで、トピックの一般的な紹介では必ずしも言及されていません。 9

    ただし、少なくとも1つのライブラリーは、同期性とエラー処理を抽象化するために総称的にこの用語を使用していますが、then機能は提供していません。 10 「約束」という用語を意図的に避けることは意図的であったかどうかは不明ですが、約束は「実現可能性」を中心に構築されているため、おそらく良い選択です。 2

参考文献

  1. 約束と未来に関するウィキペディア
  2. Promises / A +仕様
  3. DOM Standard on Promises
  4. DOM標準は仕様WIPを約束します
  5. DOJOツールキットの延期
  6. jQuery Deferreds
  7. Q
  8. FutureJS
  9. Promiseの機能Javascriptセクション
  10. AngularJS統合テストの将来

混乱を招く可能性のあるその他の事項


5
「未来」という用語をもう少し明確にするために– 80年代半ばまでさかのぼって、多くのプログラミング言語にわたって未来には長い歴史があります。そしてこの用語は今日でも、特にJVMで広く使われています。JavaScriptは、「将来」というJavaの意味に似た意味で「約束」という用語を使用することを選択したようです。Scalaは、同じ概念を「Future」と「Promise」に分けて、JavaScriptプログラマーがPromiseと呼ぶものの「読み取り」ハンドルと「書き込み」ハンドルを参照します。
ヘザーミラー

1
そしてもちろん、Microsoftはそれのために独自の用語を思い付くしなければならなかったので、C#で、彼らが呼ばれているTask
BlueRaja -ダニーPflughoeft

72

私にとって本当にクリックしたのは、Domenic Denicolaによるこのプレゼンテーションでした。

githubのの要旨、彼はほとんどのような説明のIを与え、それは非常に簡潔です。

約束のポイントは、非同期の世界で機能的な構成とエラーのバブリングを返すことです。

つまり、プロミスは、あたかも同期であるかのように簡単に記述できる非同期コードを記述できる方法です。

次の例で、約束を考えてみましょう。

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);
}

(これでも複雑に聞こえる場合は、そのプレゼンテーションをご覧ください!)

Deferredに関しては、それは方法.resolve()または.reject()約束です。で約束/ Bの仕様、それが呼び出されます.defer()。jQueryでは$.Deferred()です。

私の知る限り、jQuery 1.8.2以降では、jQueryでのPromiseの実装が壊れている(その要旨を参照)ことに注意してください。
おそらくPromises / A thenablesを実装していますが、「非同期のtry / catch」機能全体が機能しないという意味で、正しいエラー処理が得られません。これは残念なことです。非同期コードを使用して "試行/キャッチ"を行うのは非常にクールだからです。

Promiseを使用する場合(独自のコードで試してみてください!)、Kris KowalのQを使用してください。jQueryバージョンは、よりクリーンなjQueryコードを作成するためのコールバックアグリゲーターですが、要点を逃しています。

Futureについては、私にはわかりません。どのAPIでもそれを見たことがありません。

編集: 約束のDomenic Denicolaのユーチューブ話から@farm以下のコメント。

ビデオからのマイケルジャクソンからの引用(そう、マイケルジャクソン):

私はあなたにこのフレーズをあなたの心に焼き付けて欲しい: 約束は非同期の値です。

これは優れた説明です。約束は未来からの変数のようなものです。ある時点で存在する(または発生する)ものへのファーストクラスの参照です。


5
W3およびChromeコアチームのメンバーによるFutures(現在はDOMに実装されています!)の優れた説明は、xanthir.com
オリゴフレン

1
@oligofrenリンクありがとうございます。ちなみに、なんと不思議な迷惑なファビコン笑。
Camilo Martin

1
この回答にはもっと多くの賛成票が必要です。承認された回答IMOより高い投票が必要です。
Chev 2013年

1
Domenic Denicolaのyoutubeトークon Promises:youtube.com/watch
ファーム

@ファームグレート!それを答えに追加します。
Camilo Martin、

32

A プロミスは、約束が作成されるときに必ずしも知られていない値のプロキシを表します。ハンドラーを非同期アクションの最終的な成功値または失敗理由に関連付けることができます。これにより、非同期メソッドは同期メソッドのように値を返すことができます。非同期メソッドは、最終的な値の代わりに、将来のある時点で値を持つという約束を返します。

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise

このdeferred.promise()メソッドにより、非同期関数は、他のコードがその内部要求の進行またはステータスを妨害するのを防ぐことができます。Promiseは、追加のハンドラーをアタッチするか、状態を決定するために必要なDeferredメソッドのみを公開し(その後、done、fail、always、pipe、progress、state、promise)、状態を変更するメソッドresolve、reject、notify、resolveWith、 rejectWith、notifyWithなど)。

ターゲットが指定さdeferred.promise()れている場合、その上にメソッドをアタッチし、新しいオブジェクトを作成するのではなく、このオブジェクトを返します。これは、Promiseビヘイビアーを既存のオブジェクトにアタッチするのに役立ちます。

Deferredを作成する場合は、Deferredへの参照を保持して、ある時点で解決または拒否できるようにします。他のコードがコールバックを登録したり、現在の状態を検査できるように、deferred.promise()を介してPromiseオブジェクトのみを返します。

単純に、Promiseはまだ知られていない値を表し、Deferredはまだ完了していない作業を表すと言えます。


ここに画像の説明を入力してください


1
プラス1はグラフを表します。ブラビシモ!! ^ _ ^
Ashok MA、

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.