JavaScriptにおけるPromise Hell問題
既にご存知のように、プロミスはcallback hell問題を解決するために作られました。 しかし、時が経つにつれ、プロミスもまた複雑なコードを生み出す可能性があることがわかりました。 この問題はアナロジーとしてpromise hellと名付けられました。
コード例を通じてこの問題を見てみましょう。
パラメータを受け取り、そのパラメータに応じて結果を返す関数getSmthがあるとします:
function getSmth(num) {
return new Promise((resolve, reject) => {
setTimeout(() => resolve(num * num), 1000)
});
}
この場合、私たちは何らかの有用な操作(例えばサーバーからのデータ取得)をシミュレートしています。 シミュレーションとして、単に数値をパラメータとして渡し、1秒後にその数値の2乗を返します。
では、別の関数内でこの関数getSmthを使ってみましょう:
function func() {
getSmth(2).then(res => {
console.log(res); // 4を出力
});
}
func();
第一の問題
連続する多数のthen構造は、コードの理解を困難にします:
function func(){
getSmth(2).then(res1 => {
// 何かを行う
}).then(res2 => {
// 何かを行う
}).then(res3 => {
// 何かを行う
}).then(res4 => {
// 何かを行う
}).then(res5 => {
// 何かを行う
}).then(res6 => {
// 何かを行う
});
}
func();
第二の問題
別種類の問題もあります。 今度は、私たちの関数を2回使用し、その結果を合計したいとします。 その結果、以下のようなコードになります:
function func() {
getSmth(2).then(res1 => {
getSmth(3).then(res2 => {
console.log(res1 + res2); // 13を出力
});
});
}
func();
もうcallback hellを思い出させますね? もう1回関数呼び出しを追加すると、コードはさらに悪化します:
function func() {
getSmth(2).then(res1 => {
getSmth(3).then(res2 => {
getSmth(4).then(res3 => {
console.log(res1 + res2 + res3);
});
});
});
}
func();
もちろん、Promise.allを利用することもできます:
function func() {
Promise.all([getSmth(2), getSmth(3), getSmth(4)]).then(res => {
console.log(res[0] + res[1] + res[2]);
});
}
func();
しかし、同じ結果が得られたでしょうか? いいえ! 最初のケースでは、各新しい関数は前のプロミスの完了を待ちますが、 2番目のケースでは、すべてのプロミスが同時に実行されます。 この違いは、次の関数に前の呼び出し結果を渡したい場合に重要になります:
function func() {
getSmth(2).then(res1 => {
getSmth(res1).then(res2 => {
getSmth(res2).then(res3 => {
console.log(res3);
});
});
});
}
func();