はい、Promiseは非同期コールバックです。それらはコールバックができないことを何もすることができません、そしてあなたは普通のコールバックと同じように非同期で同じ問題に直面します。
しかし、約束がある以上、単にコールバックより。これらは非常に強力な抽象化であり、エラーが発生しにくいボイラープレートを使用して、よりクリーンで優れた機能的なコードを実現します。
では、主なアイデアは何ですか?
Promiseは、単一の(非同期)計算の結果を表すオブジェクトです。彼らは一度だけその結果に解決します。これが意味することはいくつかあります:
Promiseはオブザーバーパターンを実装します。
- タスクが完了する前に、値を使用するコールバックを知っている必要はありません。
- 関数の引数としてコールバックを期待する代わりに
return
、Promiseオブジェクトを簡単に作成できます
- promiseは値を保存し、いつでも透過的にコールバックを追加できます。結果が利用可能になると呼び出されます。「透明性」は、promiseがあり、それにコールバックを追加しても、結果がまだ届いているかどうかに関係なくコードに影響を与えないことを意味します。APIとコントラクトは同じで、キャッシング/メモ化が大幅に簡素化されます。
- 複数のコールバックを簡単に追加できます
約束はチェーン可能です(モナド、あなたがしたい場合):
- プロミスが表す値を変換する必要がある場合は、変換関数をプロミスにマッピングし、変換された結果を表す新しいプロミスを取得します。同期して値を取得して何らかの方法で使用することはできませんが、Promiseコンテキストで変換を簡単に解除できます。ボイラープレートコールバックはありません。
- 2つの非同期タスクをチェーンしたい場合は、この
.then()
メソッドを使用できます。最初の結果で呼び出されるコールバックを受け取り、コールバックが返すプロミスの結果に対するプロミスを返します。
複雑に聞こえますか?コード例の時間。
var p1 = api1(); // returning a promise
var p3 = p1.then(function(api1Result) {
var p2 = api2(); // returning a promise
return p2; // The result of p2 …
}); // … becomes the result of p3
// So it does not make a difference whether you write
api1().then(function(api1Result) {
return api2().then(console.log)
})
// or the flattened version
api1().then(function(api1Result) {
return api2();
}).then(console.log)
平坦化は不思議なことではありませんが、簡単に行うことができます。非常にネストされた例の場合、(ほぼ)同等のものは次のようになります
api1().then(api2).then(api3).then(/* do-work-callback */);
これらのメソッドのコードを確認すると理解に役立つ場合は、数行で最も基本的なpromiseライブラリを次に示します。
約束についての大騒ぎは何ですか?
Promiseの抽象化により、関数の構成性が大幅に向上します。たとえば、then
チェーンの隣にあるall
関数は、複数の並列待機プロミスの結果を組み合わせたプロミスを作成します。
最後になりましたが、Promiseにはエラー処理が統合されています。計算の結果は、promiseが値で満たされるか、または理由で拒否されるかのいずれかです。すべての構成関数はこれを自動的に処理し、プロミスチェーンでエラーを伝播するため、プレーンコールバックの実装とは対照的に、どこでも明示的に気にする必要はありません。最後に、発生したすべての例外に対して専用のエラーコールバックを追加できます。
言うまでもなく、物事を約束に変換する必要があります。
これは、実際にはプロミスライブラリでは非常に簡単です。「既存のコールバックAPIをプロミスに変換するにはどうすればよいですか?」を参照してください。