まず then を一言でいうと
then は、
「Promise が“成功したあとにやりたい処理”を登録するための関数」
です。
Promise は「そのうち結果が入る箱」でしたね。then はその箱に対して、
「中身(成功結果)が決まったら、この関数を呼び出してね」
と約束を登録する場所です。
ここが重要です。then は「今すぐ実行する」のではなく、
「Promise が fulfilled(成功)になったタイミングで、後から非同期的に実行されるコールバックを登録するもの」
だとイメージしてください。
then の基本形と引数
一番シンプルな書き方
基本形はこうです。
promise.then(onFulfilled);
JavaScriptpromise が fulfilled になったとき、
その成功値を引数として onFulfilled が呼び出されます。
例:
const p = Promise.resolve(42);
p.then((value) => {
console.log("value:", value); // 42
});
JavaScriptPromise.resolve(42) は、「すでに fulfilled で値 42 を持っている Promise」です。
その Promise に対して then を呼ぶと、value に 42 が渡ってきます。
成功と失敗の両方を書く形
then は、第2引数に「失敗時の処理」も渡せます。
promise.then(onFulfilled, onRejected);
JavaScript例:
const p = new Promise((resolve, reject) => {
reject(new Error("失敗"));
});
p.then(
(value) => {
console.log("成功:", value);
},
(err) => {
console.log("失敗:", err.message);
}
);
JavaScriptこう書けますが、
現代の書き方では「失敗は .catch で書く」ほうが主流です。
初心者のうちは、まずは
成功 → then
失敗 → catch
と分けて覚えるほうが混乱しません。
then が呼ばれるタイミング(ここ大事)
「成功した瞬間」ではなく「イベントループのタイミングで」
次のコードを見てください。
const p = new Promise((resolve) => {
resolve("OK");
});
console.log("A");
p.then((value) => {
console.log("B:", value);
});
console.log("C");
JavaScript直感的には「A → B → C」と出そうですが、
実際はこの順です。
A
C
B: OK
理由を分解します。
Promise 作成時に resolve("OK") を呼ぶ
→ Promise はすぐに fulfilled になるconsole.log("A") が実行されるp.then(...) で「成功時の処理」が登録されるconsole.log("C") が実行される
同期処理(このファイルのコード)が終わる
イベントループが「成功済みの Promise の then コールバック」をマイクロタスクとして実行
→ 「B: OK」が出る
つまり、then の中身は「同期コードが終わったあと」に実行されます。
ここが重要です。
then に渡した関数は、「Promise が成功したタイミング」+「今のタスクが一段落したタイミング」で、非同期的に実行される
という点を覚えておいてください。
then は「Promise を返す」こと(チェーンの基本)
then の戻り値が次の処理につながる
then の一番大事なポイントは、
「then そのものが、新しい Promise を返す」
ということです。
const p = Promise.resolve(2);
const p2 = p.then((value) => {
return value * 3;
});
p2.then((v) => {
console.log(v); // 6
});
JavaScript流れはこうです。
最初の Promise p は、2 という値で fulfilled している。p.then(...) の中で value * 3(=6)を return する。
その return 値 6 が、「p2 という新しい Promise の成功値」になる。p2.then の v に 6 が渡ってくる。
つまり、then の戻り値として、
普通の値を返せば、「その値で成功した新しい Promise」になる
別の Promise を返せば、「その Promise の結果をそのまま次に流してくれる」
という性質があります。
非同期処理を順番に「直線的に」つなげられる
この性質を使うと、非同期処理をチェーンできます。
fetchUser() // Promise を返すと仮定
.then((user) => {
console.log("ユーザー:", user);
return fetchPosts(user.id); // これも Promise を返す
})
.then((posts) => {
console.log("投稿:", posts);
return fetchComments(posts[0].id); // これも Promise
})
.then((comments) => {
console.log("コメント:", comments);
})
.catch((err) => {
console.error("どこかでエラー:", err);
});
JavaScriptここでは、
fetchUser の Promise が成功 → 1つ目の then が呼ばれる
その中で fetchPosts の Promise を return → 「次の then の対象」がその Promise に変わるfetchPosts が成功 → 2つ目の then が呼ばれる
同様に fetchComments を return → 次の then がそれを待つ
というふうに、
時間の流れ(順番に非同期処理したい)が、「then の縦の列」として表現できる ようになります。
ここが重要です。
then が Promise を返すからこそ、「コールバック地獄のネスト」ではなく、「フラットなチェーン」として非同期処理をつなげられる。
これが then の本当の強みです。
then で「値を変換する」イメージ
純粋に値だけを変換するのも普通に使う
then は必ずしも「次の非同期処理」を返さなくてもよくて、
単に値を変換したいだけのときにも使えます。
Promise.resolve(5)
.then((v) => v * 2) // 10 に変換
.then((v) => `値は ${v}`) // "値は 10" に変換
.then((msg) => {
console.log(msg); // 値は 10
});
JavaScript各 then は、
渡された値を受け取る
何らかの変換をして return する
その return 値が「次の Promise の成功値」になる
という動きをします。
この「値を流しながら変換していく」イメージは、
後で async/await を使うときにもそのまま活きます。
then の第2引数より catch を使うほうがよい理由(さわりだけ)
then(onFulfilled, onRejected) も書けるが…
then の第2引数でエラー処理も書ける、と言いました。
promise.then(
(value) => { /* 成功時 */ },
(error) => { /* 失敗時 */ }
);
JavaScriptですが、これは慣れてきてもあまり使われません。
理由は、
チェーンの途中で「一部だけ」エラーをキャッチしてしまい、
後ろの then にエラーが伝わらなくなることがあるから
です。
catch を末尾につけると「エラーをまとめやすい」
そのため、基本パターンとしては、
promise
.then(...)
.then(...)
.then(...)
.catch((err) => {
console.error("どこかで失敗:", err);
});
JavaScriptという形(成功は全部 then、失敗は最後の catch)
で覚えておくほうが、全体の挙動がシンプルになります。
ここが重要です。
「成功は then」「失敗は catch」という分担で考えると、
Promise チェーンの読み方・書き方がかなりクリアになる。
初心者としての「then の押さえどころ」
最後に、今の段階でしっかり覚えておくべきポイントを整理します。
then は、「Promise が fulfilled(成功)になったときに実行する処理」を登録するためのメソッド。
then に渡したコールバックは、「すぐ」ではなく、「Promise が成功し、かつ今の同期処理が一段落したあと」に非同期的に実行される。
then は必ず新しい Promise を返す。
return した値はその新しい Promise の成功値になり、return した Promise はその結果が次の then に渡される。
これにより、複数の非同期処理を「ネスト」ではなく「チェーン(直線)」としてつなげられる。
エラー処理は基本的に .catch に任せ、「then は成功時だけ」を書く考え方にするとシンプル。
ここが重要です。
then を「成功時の続きを書く場所」+「次の Promise につなぐ橋」として捉えると、Promise 全体のイメージが一気に掴みやすくなります。
おすすめの練習は、
Promise.resolve でスタートする
then を 2〜3 個つないで、値を変換しながら最後に console.log する
といったシンプルなチェーンを書いてみることです。
「値がどう流れ、どこで変換され、どこでログに出るか」を
自分の目で確認できるようになると、
then は「難しい謎の関数」ではなく、
「結果を受けて次の一歩を書くための、素直な道具」 に見えてきます。
