はじめに
JavaScriptでの非同期処理を扱う際、Promiseチェーンは非常に強力なパターンです。しかし、その動作原理は一見すると複雑に感じられることがあります。特に「.then()メソッドの連鎖」と「Promiseの解決値」の関係は混乱しやすいポイントです。
この記事では、以下のような疑問に答えていきます:
- Promiseチェーンで値はどのように伝播するのか
- ハンドラがPromiseを返す場合と通常の値を返す場合の違い
- 「Promiseの解決」とは具体的に何を意味するのか
Promiseの基本
まず、Promiseには3つの状態があります:
- pending(保留中): 初期状態
- fulfilled(成功): 操作が成功し、値が利用可能になった状態
- rejected(拒否): 操作が失敗した状態
Promiseが「解決された」とは、そのPromiseがresolve関数を通じて値を提供した状態(fulfilled)になったことを意味します。
Promiseチェーンの動作原理
以下のコードを例に考えてみましょう:
new Promise(function(resolve, reject) {
setTimeout(() => resolve(1), 1000);
}).then(function(result) {
alert(result); // 1
return new Promise((resolve, reject) => {
setTimeout(() => resolve(result * 2), 1000);
});
}).then(function(result) {
alert(result); // 2
return new Promise((resolve, reject) => {
setTimeout(() => resolve(result * 2), 1000);
});
}).then(function(result) {
alert(result); // 4
});
このコードを理解する上で重要なポイントは以下の通りです:
1. .then()
は新しいPromiseを返す
各.then()呼び出しは新しいPromiseオブジェクトを返します。つまり、チェーンの各ステップは異なるPromiseオブジェクトです。
const promise1 = new Promise(...);
const promise2 = promise1.then(...); // 新しいPromise
const promise3 = promise2.then(...); // さらに新しいPromise
2. ハンドラの戻り値が次の.then()に渡される
.then()に渡されるハンドラ関数の戻り値によって、次の.then()の動作が決まります:
ハンドラが通常の値を返す場合:その値で即座に解決されたPromiseが生成され、値がすぐに次の.then()に渡されます。
ハンドラがPromiseを返す場合:そのPromiseが解決されるまで待ち、解決値が次の.then()に渡されます。
混乱しやすいポイントの解説
最初に混乱しやすいのは、「Promiseの解決値」と「Promiseオブジェクト自体」の区別です。
.then(function(result) {
// ここでのresultは前のPromiseの「解決値」であり、Promiseオブジェクト自体ではない
return new Promise((resolve, reject) => {
setTimeout(() => resolve(result * 2), 1000);
});
})
このハンドラが返すPromiseは、次の.then()にそのまま渡されるわけではありません。代わりに、このPromiseが解決されるのを待ち、その解決値が次の.then()のハンドラに渡されます。
具体例で理解する
先ほどの例の実行フローを詳しく見てみましょう:
- 最初のPromiseが1秒後にresolve(1)で解決される
- 最初の.then()ハンドラが実行され、resultに1が入る
- alert(1)が実行される
- 新しいPromiseを返す(このPromiseは1秒後に2で解決される)
- 1秒待機
- 返されたPromiseが2で解決されると、次の.then()ハンドラが実行される
- resultに2が入る(前のPromiseの解決値)
- alert(2)が実行される
- 再び新しいPromiseを返す(このPromiseは1秒後に4で解決される)
- 1秒待機
- そのPromiseが4で解決されると、最後の.then()ハンドラが実行される
- resultに4が入る
- alert(4)が実行される
重要な結論
Promiseチェーンを理解する上で最も重要なのは、.then()に渡されるのは常に「解決値」であり、Promiseオブジェクト自体ではないということです。
ハンドラが通常の値を返す場合とPromiseを返す場合の違いは、単に「次の.then()が実行されるタイミング」だけです:
- 通常の値を返す場合:即座に次の.then()が実行される
- Promiseを返す場合:そのPromiseが解決されるまで待ってから次の.then()が実行される
結果として渡される値は同じであり、違いは「いつ次の処理が実行されるか」だけなのです。
まとめ
Promiseチェーンは、非同期処理を順序立てて実行するための強力なメカニズムです。各.then()は前のステップの結果を受け取り、次のステップに値を渡していきます。
Promiseを返すことで「この処理が終わるまで待ってから次に進む」という制御ができ、これによりコールバック地獄を避けながら読みやすく保守しやすいコードを書くことができます。
Promiseチェーンの本質を理解すれば、複雑な非同期処理も明確に構造化できるようになります。