ここまでで、promiseオブジェクトが Fulfilled または Rejected となった時の処理は .then
と .catch
で登録でき、 .finally
を使うことで Fulfilled と Rejected どちらの場合でも実行される処理を登録できることを学びました。
一つのpromiseオブジェクトなら、そのpromiseオブジェクトに対して処理を書けばよいですが、 複数のpromiseオブジェクトが全てFulfilledとなった時の処理を書く場合はどうすればよいでしょうか?
たとえば、複数のXHR(非同期処理)が全て終わった後に、何かをしたいという事例を考えてみます。
少しイメージしにくいので、 まずは、通常のコールバックスタイルを使って複数のXHRを行う以下のようなコードを見てみます。
Warning
|
CORSについて
ブラウザにおけるXHRのリソース取得には、CORS(Cross-Origin Resource Sharing)というセキュリティ上の制約が存在します。 このCORSの制約により、ブラウザでは同一ドメインではないリソースを許可なく取得することはできません。そのため、一般的には別サイトのリソースは許可なくXHRでアクセスすることができません。 次のサンプルでは
また、 httpbin.org というドメインがリソース取得の例として登場します。 こちらも、同一ドメインでなくてもリソースの取得が許可されています。 |
link:embed/embed-multiple-xhr-callback.js[role=include]
// 実行例
main(function(error, results){
if(error){
console.error(error);
return;
}
console.log(results);
});
このコールバックスタイルでは幾つかの要素が出てきます。
-
JSON.parse
をそのまま使うと例外となるケースがあるためラップしたjsonParse
関数を使う -
複数のXHRをそのまま書くとネストが深くなるため、
allRequest
というrequest関数を実行するものを利用する -
コールバック関数には
callback(error,value)
のように第一引数にエラー、第二引数にレスポンスを渡す。
jsonParse
関数を使うときに bind
を使うことで、部分適用を使って無名関数を減らすようにしています。
(コールバックスタイルでも関数の処理などをちゃんと分離すれば、無名関数の使用も減らせると思います)
jsonParse.bind(null, callback);
// は以下のように置き換えるのと殆ど同じ
function bindJSONParse(error, value) {
jsonParse(callback, error, value);
}
コールバックスタイルで書いたものを見ると以下のような点が気になります。
-
明示的な例外のハンドリングが必要
-
ネストを深くしないために、requestを扱う関数が必要
-
コールバックがたくさんでてくる
次は、Promise#then
を使って同様のことをしてみたいと思います。
先に述べておきますが、Promise.all
というこのような処理に適切なものがあるため、
ワザと .then
の部分をクドく書いています。
.then
を使った場合は、コールバックスタイルと完全に同等というわけではないですが以下のように書けると思います。
link:embed/embed-multiple-xhr.js[role=include]
// 実行例
main().then((value) => {
console.log(value);
}).catch((error) => {
console.error(error);
});
コールバックスタイルと比較してみると次のことがわかります。
-
JSON.parse
をそのまま使っている -
main()
はpromiseオブジェクトを返している -
エラーハンドリングは返ってきたpromiseオブジェクトに対して書いている
先ほども述べたように mainの then
の部分がクドく感じます。
Promiseでは、このような複数の非同期処理をまとめて扱う Promise.all
と Promise.race
という静的メソッドが用意されています。
次のセクションではそれらについて学んでいきましょう。