2017-07-13 10 views
1

私は複数のWebサイトで、promise.prototypeの.then()メソッドが約束を返すことを読みました。残念なことに、これの背後にある理由を説明する情報源はありません。.then()メソッドによって返されるpromiseオブジェクトの目的は何ですか?

次に、()メソッドはPromiseを返します。プロミスの成功と失敗の場合のコールバック関数は、最大2つの引数をとります。 - developer.mozilla.com

なぜ/誰がこの返された約束オブジェクトを必要とするのでしょうか?この約束オブジェクトは元のオブジェクトにどのように関連していますか?

ありがとうございました。

+0

私はカイルシンプソンの本「あなたが知らないJS:非同期&パフォーマンス」をお勧めします。それは、連鎖のような明白なものを越えて、約束の利益について詳細に説明します。 –

答えて

5

約束事は非同期で実行され、then()がいつ実行されるかはわかりません。

約束は約束を返すことができるので、非同期イベント処理を1行のコードで連鎖させることができます。

Mozillaが与えられた例コード:これはPromisseの良い部分である

doSomething(function(result) { 
    doSomethingElse(result, function(newResult) { 
    doThirdThing(newResult, function(finalResult) { 
     console.log('Got the final result: ' + finalResult); 
    }, failureCallback); 
    }, failureCallback); 
}, failureCallback); 

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises

+0

ねえ、どうやって非同期的に実行されていますか?あなたの素晴らしい答えに感謝します。 – JohannaNoobie

+1

シングルスレッドのJavascriptは、コードを非同期的に実行します。コードの一部は実行されますが、他のものはブロックされている可能性があります(たとえば、ネットワーク要求への応答を待つ)。実行者は、イベントが受信されたときに切り替わり、イベントが処理されるときに他のコード部分の実行を再開する。 – Fabien

+0

イベントが受信されたときに切り替わり、その後に再開し、非同期I/OがブロックしていないJavascript実行プログラムはありません。これは、Javascriptのイベントドリブンロジックがどのように機能するかではありません。イベントは実行中の他のコードを中断しません。代わりに、Javascriptの実行中の部分が実行を終了するまで実行されます。次に、インタプリタはイベントキューをチェックして、実行する別のイベントがあるかどうかを確認し、そうであれば、次のイベントを実行します。何も実行されておらず、イベントが(一部のネイティブコードによって)イベントキューに追加された場合、そのイベントが実行されます。 – jfriend00

0

doSomething().then(function(result) { 
    return doSomethingElse(result); 
}) 
.then(function(newResult) { 
    return doThirdThing(newResult); 
}) 
.then(function(finalResult) { 
    console.log('Got the final result: ' + finalResult); 
}) 
.catch(failureCallback); 

これは "運命のピラミッド" を回避します。

上記のメソッド結果(この場合はPromisse.resolve)に依存するメソッドを多数チェーンすることができます。同様にthis

1

.then()が約束を返すという3つの主な側面があります。その新しい約束が解決するまで

a().then(b).then(c).then(d) 

.then()が新たな約束を返すので、以下の.then()ハンドラが実行されません。

最初は、あなたがこのようなチェーンオペレーションができるということです。 bとcが同期していれば、新しい約束はそれらが戻るときに解決され、最初にbが完了した後、そしてcが完了したときにチェーンが続行されます。

第2のは、新しい約束事が.then()ハンドラが返すものの影響を受けることができるということです。これにより、b、c、dは非同期操作になり、それ自身は約束を返し、チェーンは適切に順序付けされます。だから、bとcの両方が約束を返すと想像してください。

まず、a()に約束を返します。解決されると、その.then()ハンドラが呼び出されます。それはbを実行します。 b()も非同期操作であり、新しい約束を返す場合、a.then(b)は、返された新しい約束が解決されるまで、他のすべての.then()ハンドラがリンクされていることを返します。これにより、.then()ハンドラは新しい非同期アイテムをチェーンに挿入できます。これは約束の連鎖の非常に重要な側面です。.then()ハンドラは、独自の非同期操作をチェーンに挿入することができ、以前の結果や現在の状態に基づいて条件付きで行うこともできます。

a().then(b)はちょうど彼らがa()約束にリンクされていたであろうと、それはすでに解決したので、a()リターンは、その後、後続のすべての.then()ハンドラがそのb()リターンの約束のために、「待つ」ことができないだろうと同じ約束を返された場合。その新しい約束は、.then()ハンドラが返すものの影響を受けるので、.then()ハンドラ内の関数が後続のチェーンに影響を与えることを可能にするこの新しい約束の返却です。

第三側面は.then()ハンドラの戻り値は、新たな約束の解決された値に影響を与えることができるということであり、それはチェーンの次の.then()ハンドラに渡されるものです。 a()が返す同じ約束を返したばかりの場合、a()ハンドラはa()から同じ解決された値を参照するだけです。a()が解決された時点ですでに解決済みの値が設定されています。.then()ハンドラこれらの後続の.then()ハンドラは、.then()ハンドラ内のコードから新しい解決された値を継承することができません。


具体的なシナリオを見てみましょう。私は遅延メソッドを、将来解決する約束を返す関数の簡単な例として使用します。

その後
function delay(t, val) { 
    return new Promise(resolve => { 
     setTimeout(() => resolve(val), t); 
    }); 
} 

、いくつかの異なる非同期関数を定義する:

function a(val) { 
    return delay(100, val + 1); 
} 

function b(val) { 
    return delay(50, val + 10); 
} 

function c(val) { 
    return val * 100; 
} 

、チェーンにそれらをすべて入れ:

a(100).then(b).then(c).then(val => { 
    console.log("all done: ", val); 
}); 

はここで段階的に何が起こるかです:

  1. a(100)はcalle d。これはdelay(タイマーを設定します)を呼び出し、ここで説明するために私がa1_promiseと呼ぶ約束を返します。

  2. 我々はa(100).then(b)をやっているので、その後、我々はa1_promiseとコールa1_promise.then(b)あるa(100)からの戻り値を取ります。これはa1_promiseが解決されたときにいつか呼び出される関数を.then()ハンドラ関数として保存します(現時点ではそうではありません)。そしてそれは私がa2_promiseと呼ぶ新しい約束を返します。

  3. 我々はa(100).then(b).then(c)をやっているので、その後、我々はa2_promiseとコールa2_promise.then(c)あるa(100).then(b)からの戻り値を取ります。 a2_promiseが解決された時点で、.then()ハンドラ関数としてcファンクションがいつか呼び出されるようになりました。それから、私はa3_promiseと呼ぶ新しい約束を返します。

  4. 我々はa(100).then(b).then(c).then(...)をやっているので、その後、我々はa3_promiseとコールa3_promise.then(c)あるa(100).then(b),then(c)からの戻り値を取ります。これは、a3_promiseが解決されたとき(将来はいつでも)、いつか呼び出される.then()ハンドラ関数として最後の無名関数を格納します。その後、私はa4_promise(誰も使用しない)と呼ぶ新しい約束を返します。

  5. これで同期実行が完了しました。 a().then(b).then(c).then(...)はすべて同期して実行されていたことに注意してください。すべての3つの.then()メソッドは既にすべての異なる約束で呼び出されています。しかし、ここで作成された約束はまだ解決されていないので、.then()ハンドラのどれも実際にはまだ呼び出されていません。約束が解決されたときに、彼らはすべて、将来呼び出されるようになったばかりです。

  6. a()の内部で作成されたタイマーが起動し、a1_promiseが解決されました。その後、a1_promiseをトリガして、.then()ハンドラを呼び出し、a1_promiseという解決済みの値(この場合は100 + 1または101)を渡します。 a1_promiseにはただ1つの.then()ハンドラがあり、それはb()関数ですので、今度はb(101)を呼び出します。それを実行すると、b()が作成して返した新しい約束が返されます。我々はその新しい約束をb_promiseと呼ぶでしょう。 a1_promise()内部には、それが保存されていること.then()ハンドラを実行し、.then()ハンドラが新しい約束を実行し、返すことをするとき、それはa2_promise that it created until that b_promise is resolved. In this way, you can see that further execution of the chain is now controlled by the b_promise , thus the code executing in Bの解決にオフに保持していることを知っているようa1_promise.then()が以前に呼び出されたとき、それはa2_promise()を作成したことを知っています()and the promise is returned are inserted into the a()。then()。then()。then()chain holding off future .then()handlers until the b_promise`が解決されました。

  7. は現在、いくつかのより多くの時間が経過すると、タイマーはb()火災の内部で作成され、111ある101 + 10の新しく変更された値を持つb1_promiseを解決します。これにより、a2_promiseはその値で解決できるようになります。

  8. a2_promiseは、それが.then()ハンドラだ呼び出すことができますし、もう一度だけc_promise 6リターンステップのように、まだ解決されていないc(111)を実行することができます。

  9. いくつかの時間が経過するとc_promiseは今、その値に解決できることを111 * 100 which is 11,100 . That tells the a3_promise`の値を解決します。それを呼び出すことができます

  10. a3_promiseはチェーンの終わりに私たちの矢印機能がある.then()ハンドラだと我々は最終的な値として示すconsole.log()11000を取得します。

関連する問題