then()からの戻り値またはPromise.resolveの違いは何ですか


314

違いは何ですか:

new Promise(function(res, rej) {
    res("aaa");
  })
  .then(function(result) {
    return "bbb";
  })
  .then(function(result) {
    console.log(result);
  });

この:

new Promise(function(res, rej) {
    res("aaa");
  })
  .then(function(result) {
    return Promise.resolve("bbb");
  })
  .then(function(result) {
    console.log(result);
  });

.then()のチェーニングでAngularと$ httpサービスを使用して異なる動作を取得しているので、質問しています。少しコードが多すぎるため、最初に上記の例を使用します。


1
あなたはどんな「異なる行動」を見ていますか?どちらの例も機能し、ほぼ同じように動作します。Promise.resolve()第二の例では不要です。
JLRishe 2014

4
@pixelbits thenハンドラーからpromiseを返すことには何の問題もありません。実際、それはあなたができるpromise 仕様の重要な側面です。

これは、任意にネストされたthensで機能することに注意してください。これに対する「他の言語」の用語thenは、a mapとaの両方flatMapです。
Benjamin Gruenbaum 2014

1
2行目で、なぜres( "aaa")を呼び出さなければならないのか、なぜ "aaa"を返せないのか、そしてresolve()のPromiseはreject()の例外をキャッチするのと同じ方法でキャッチしますか?
Sam Liddicott

1
@SamLiddicottは同じ質問を持っていますが、鉱山はもう少し複雑です:new Promise((res, rej) => { return fetch('//google.com').then(() => { return "haha"; }) }).then((result) => alert(result));このコードはハングするだけです(永久に解決されるわけではありません)。しかし、私return "haha";return res("haha");それに変更した場合、それは機能し、「ハハ」に警告します。fetch()。then()はすでに「ハハ」を解決済みのプロミスにラップしていませんか?
ショーンチェン

回答:


138

ルールは、 thenハンドラはその値を持つ値、約束の解決さ/拒否を返し、関数が約束を返した場合、何が起こるかで、次のthen句は次のようになりますthenの句返される関数を約束します、したがって、この場合、最初の例はの通常のシーケンスを通り抜け、thens期待どおりに値を出力します。2番目の例では、実行したときに返されるpromiseオブジェクトPromise.resolve("bbb")は、then連鎖したときに呼び出されるpromiseオブジェクトです(すべての意図と目的のために)。実際に機能する方法については、以下で詳しく説明します。

Promises / A +仕様からの引用:

promise解決手続きは、promiseとvalueを入力として受け取る抽象的な操作であり、と表記し[[Resolve]](promise, x)ます。もしx thenableがあり、それは約束を作るしようとするの状態を採用しx、少なくとも多少の約束のように振る舞うのxは仮定の下で、。それ以外の場合は、その値で約束を満たしますx

thenablesのこの処理により、Promises / A +準拠のthenメソッドが公開されている限り、promise実装の相互運用が可能になります。また、Promises / A +実装は、妥当なthenメソッドを使用して、非準拠の実装を「同化」することができます。

ここで注目すべき重要な点は、次の行です。

もし x約束で、その状態を採用する [3.4]

リンク:https : //promisesaplus.com/#point-49


4
「その状態を採用」は、thenハンドラーがpromiseを返したときの動作を表現する簡潔で便利な方法です。スペック参照の場合は+1。

69
実際-ここでの仕様の関連部分は、表と値の[[Resolve]]両方で呼び出されるという事実でありthen、本質的には値をpromiseでラップするので、値はpromise return "aaa"と同じreturn Promise.resolve("aaa")return Promise.resolve("aaa")あり、同じreturn Promise.resolve(Promise.resolve("aaa"))です。一度より同じ結果を持っています。
Benjamin Gruenbaum 2014

8
@Benjamin Gruenbaumは、そのリターンを意味しているの"aaa"return Promise.resolve("aaa")では互換性がありますthenいずれの場合もABLES?
CSnerd

9
はい、まさにそれが意味します。
Benjamin Gruenbaum

118

簡単に言えば、thenハンドラー関数内で:

A)xが値(数値、文字列など)の場合:

  1. return x に相当 return Promise.resolve(x)
  2. throw x に相当 return Promise.reject(x)

B)xすでに解決済みのプロミス(いつでも保留されていない)の場合:

  1. return xreturn Promise.resolve(x)Promiseがすでに解決されている場合、と同等です。
  2. return xreturn Promise.reject(x)Promiseがすでに拒否されている場合、と同等です。

C)x保留中の約束はいつですか:

  1. return x保留中のPromiseが返され、後続ので評価されthenます。

このトピックの詳細については、Promise.prototype.then()ドキュメントをご覧ください


93

どちらの例もほぼ同じように動作するはずです。

then()ハンドラー内で返される値は、そのハンドラーから返されるpromiseの解決値になりthen()ます。内部で返される値.then がpromiseの場合、によって返されるpromiseは、そのpromiseのthen()「状態を採用」し、返されたpromiseと同じように解決/拒否します。

最初の例で"bbb"は、最初のthen()ハンドラに戻り"bbb"、次のthen()ハンドラに渡されます。

2番目の例では、値"bbb"で直ちに解決されるpromiseを返すため"bbb"、次のthen()ハンドラーに渡されます。(Promise.resolve()ここは無関係です)。

結果は同じです。

実際に異なる動作を示す例を示すことができれば、なぜそれが起こっているのかを説明できます。


1
素敵な答え!何についてのPromise.resolve();return;
FabianTe 2018年

2
@FabianTeこれらは、のundefined代わりにを除いて、同じ効果があり"bbb"ます。
JLRishe

51

あなたはすでに良い正式な答えを得ました。私は短いものを追加する必要があると考えました。

次の事項は、Promises / A +のpromiseと同じです。

  • 呼び出しPromise.resolve(Angularの場合、$q.when
  • promiseコンストラクターを呼び出し、そのリゾルバーで解決します。あなたの場合はそれnew $qです。
  • thenコールバックから値を返します。
  • 値を持つ配列でPromise.allを呼び出してから、その値を抽出します。

したがって、以下はすべてプロミスまたはプレーンバリューXと同じです。

Promise.resolve(x);
new Promise(function(resolve, reject){ resolve(x); });
Promise.resolve().then(function(){ return x; });
Promise.all([x]).then(function(arr){ return arr[0]; });

そして当然のことですが、promiseの仕様はPromise解決手順に基づいており、ライブラリ間の相互運用が容易になり($ qやネイティブのpromiseなど)、全体的な作業が簡単になります。約束の解決が行われる可能性がある場合は常に、全体的な一貫性を作成する解決が行われます。


何をする意味があるのPromise.resolve().then(function(){ return x; });でしょうか?私は同様のことをしているのを見つけました(thenブロック内の関数と呼ばれています)。だいたいタイムアウトのようだと思ったのですが、少し速いです。jsben.ch/HIfDo
サンプガン

99.99%のケースでPromise.resolve(x)と同じであるという意味はありません。(0.001%は、例外をスローするプロパティアクセサーを使用withしてオブジェクトまたはプロキシのブロック内にいることxです。その場合、Promise.resolve(x)はエラーをスローしますがPromise.resolve().then(function(){ return x; });、エラーがスローされるため、プロミスは拒否されます。でthen)。
ベンジャミングレンバウム

空の電撃をリンクした、または保存しなかった。とにかく、私は発言の違いについて話していませんでした。私は自分が書いたことについて正確に話していました。より明確にするために、これは私が話していたスニペットです:if (validator) { Promise.resolve().then(() => { this._cdRef.markForCheck(); }); }。ここでは約束が割り当てられていないので、ポイントは何ですか?タイムアウトは(多かれ少なかれ)同じ効果をもたらすでしょうか?
サンプガン

1
すべての同期コードが発生した後、I / Oが発生する前に非同期で呼び出しを実行します。これは「マイクロティックセマンティクス」と呼ばれます。
ベンジャミングレンバウム

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