Promise
sの研究に没頭すると、議論されていない次の質問で私の理解が止まりました(私が見つけたのはPromise
コンストラクターとPromise
'then
'関数の特定の議論だけですが、設計パターンを比較する議論はありません) )。
1。 Promise
コンストラクター
MDNドキュメントから 、Promiseコンストラクターのこの使用法があります(コメントを追加):
new Promise(function(resolve, reject) { ... }); // <-- Call this Stage 1
2つの引数
resolve
およびreject
を持つ関数オブジェクト。最初の引数は約束を満たし、2番目の引数はそれを拒否します。操作が完了したら、これらの関数を呼び出すことができます。
2。 then
関数
then
オブジェクト(新しいPromise
オブジェクトを返す)で呼び出すことができるPromise
関数に移動すると、 次の関数ドキュメントに記載されている署名 (私のコメントを追加)::
p.then(onFulfilled, onRejected);
連鎖
then
メソッドはPromiseを返すため、簡単に連鎖して呼び出しできます。
var p2 = new Promise(function(resolve, reject) {
resolve(1); // <-- Stage 1 again
});
p2.then(function(value) {
console.log(value); // 1
return value + 1; // <-- Call this Stage 2
}).then(function(value) {
console.log(value); // 2
});
私の質問
上記のコードスニペットから、ステージ1でresolve
関数に渡された値(2番目のresolve
-の下( 2)、上記)は、次のステージ(同じコードスニペットで続く最初のthen
関数)に渡されます。 ステージ1には戻り値はありません。ただし、ステージ2では戻り値です。その後の次のステージに渡されます(2番目のthen
関数)。
Promise
を作成するための設計パターンと、既存のpromise(then
も返す)でのPromise
関数の使用と、単なる歴史的な問題(コールバックを呼び出す必要があるが何も返さない)もう一方は値を返しますが、コールバックを呼び出しません)?
または、Promise
コンストラクターがthen
関数とは異なる設計パターンを使用する根本的な理由がありませんか?
Bergiの答え は素晴らしく、とても助けになりました。この答えは彼を補完するものです。 Promise()
コンストラクターとthen()
メソッドの関係を視覚化するために、この図を作成しました。それが誰かの助けになることを願っています...多分私も、今から数ヶ月後。
ここでの主なアイデアは、Promise()
コンストラクターに渡される "executor"関数が、約束のset the stateを実行するタスクを設定することです。一方、then()
に渡すハンドラーは、約束の状態に反応するになります。
( Jake Archibaldの古典的なチュートリアル から適合したコード例)
これは、物事の仕組みを非常に簡略化したビューであり、多くの重要な詳細は省略されています。しかし、意図した目的の概要を把握しておくことができれば、詳細を理解するときに混乱を避けることができます。
重要な詳細の1つは、Promise()
コンストラクターに渡されるexecutor関数がimmediately(コンストラクターがプロミスを返す前に)と呼ばれることです。一方、then()
メソッドに渡されたハンドラー関数は、later(ある場合)まで呼び出されません。
Bergiはこれについて言及しましたが、a/synchronouslyの用語を使用せずに再説明したかったので、注意深く読んでいない場合は混乱する可能性があります:関数calling何かの非同期的な区別vs.非同期的に呼び出されるは、通信で簡単に見直すことができます。
resolve()
はonFulfill()
ではありませんしばらく混乱していたため、強調したいもう1つの詳細は、resolve()
およびreject()
コールバックがPromise()
コンストラクターのエグゼキューター関数に渡されることです。 are not後でthen()
メソッドに渡されるコールバック。振り返ってみると、これは明らかなように思えますが、見た目のつながりが長すぎるために円を描くようになりました。接続は確かにありますが、ゆるく、動的な接続です。
代わりに、resolve()
およびreject()
コールバックは関数です"system"によって提供されますであり、Promise
によってexecutor関数に渡されます約束を作成するときのコンストラクタ。 resolve()
関数が呼び出されると、潜在的にプロミスの状態を変更するシステムコードが実行され、最終的にonFulfilled()
コールバックが非同期に呼び出されます。 resolve()
を呼び出すことは、onFulfill()
を呼び出すためのタイトなラッパーとは思わないでください!
Promise
コンストラクターとthen
メソッドは、異なる目的のために設計された2つの独立したものであるため、対応していません。
Promise
コンストラクターは promisifying にのみ使用されます1 非同期関数。実際、あなたが言うように、 invoking resolve
/reject
asynchronously send へのコールバックに基づいて構築されます。値、およびその場合の戻り値はありません。
Promise
コンストラクター自体がこの「リゾルバー」コールバック(resolve
とreject
を同期的に渡す)を取ることは、実際には古い deferred pattern 、および意図しない類似性then
コールバックに対して。
var p = new Promise(function(res, rej) { | var def = Promise.Deferred();
setTimeout(res, 100); | setTimeout(def.resolve, 100);
}); | var p = def.promise;
対照的に、then
コールバックは従来の非同期コールバックであり、 追加機能 からreturn
を使用できます。 非同期的に呼び出されるから receive の値。
p.then(function(val) { … });
違いをまとめるには:
Promise
はコンストラクターであり、then
はメソッドですPromise
は1つのコールバックを取り、then
は2つまでかかりますPromise
はコールバックを同期的に呼び出し、then
はコールバックを非同期的に呼び出しますPromise
は常にそのコールバックを呼び出します。then
は、コールバックを呼び出さない場合があります(約束が満たされない/拒否されない場合)Promise
は、コールバックに対するプロミスを解決/拒否する機能を渡します。then
は、要求されたプロミスの結果値/拒否理由を渡しますPromise
は、副作用を実行する目的でコールバックを呼び出します(reject
/resolve
を呼び出します)。then
は、結果値のコールバックを呼び出します(チェーン用)はい、どちらも約束を返しますが、他の多くの関数とその特性を共有しています(Promise.resolve
、Promise.reject
、fetch
、…)。実際、これらはすべて、Promise
コンストラクターが提供するものと同じプロミス構築および解決/拒否機能に基づいていますが、それは主な目的ではありません。 then
は基本的に、onFulfilled
/onRejected
コールバックを既存のpromiseにアタッチする機能を提供します。これはPromise
コンストラクターに相当します。
両方がコールバックを利用するのは偶然です-歴史的な発言ではなく、言語機能の協調。
1:理想的には、すべてのネイティブ非同期APIがpromiseを返すため、これは必要ないでしょう
Promiseコンストラクターのエグゼキューター関数のポイントは、resolveおよびreject関数を非プロミス使用コードに広め、それをラップし、プロミスを使用するように変換することです。これを同期関数のみに制限したい場合は、はい、関数からの戻り値を代わりに使用できますが、リゾルバーを配布し、実際に後で実行されるコードに関数を拒否することは愚かなことです(帰国後の道)、例えば非同期APIに渡されるコールバックへ。
以前の回答に触発された(私が最も混乱した部分に対処します):
Promiseコンストラクターのresolve
およびreject
引数は、ユーザーが定義する関数ではありません。それらを非同期操作コード(通常は成功応答のresolve
と失敗理由のreject
)に埋め込むフックと考えると、javascriptが最終的にPromiseをマークする方法を持ちます。非同期操作の結果に応じて、履行済みまたは拒否として;それが発生すると、then(fun1, fun2)
で定義した適切な関数がトリガーされ、Promiseが消費されます(Promiseが履行/拒否されたかどうかに応じて、fun1(success_response)
またはfun2(failure_reason)
のいずれか)。 fun1
およびfun2
は単純な古いjavascript関数であり(非同期操作の将来の結果を引数として取得するだけです)、return
値(明示的に返さない場合はundefined
にできます) 。
Mozillaのすばらしい記事もご覧ください。
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise