Day 57:Promise
Day 57では、第5フェーズ「非同期処理とAPI」の中心的なテーマの1つである Promise を学びます。Day 56では、同期処理と非同期処理の違いを学びました。そこでは、同期処理は順番に1つずつ進む処理であり、非同期処理は時間のかかる処理を待っている間にも他の処理を進められる仕組みだと整理しました。Day 57では、その非同期処理をより整理して、わかりやすく、安全に扱うための仕組みとして Promise を学びます。
Promise は、初心者の方が最初に見ると少し難しく感じやすいです。なぜなら、今までのように「その場ですぐ値が返る処理」とは違い、「あとで結果が返るかもしれない処理」を扱うからです。しかし、考え方そのものはそこまで複雑ではありません。Promise は簡単に言えば、「未来の結果を約束として持っておく仕組み」です。成功するかもしれないし、失敗するかもしれないけれど、とにかく結果が出たらそれに応じて処理できるようにしておく、という考え方です。
このDay 57で本当に大切なのは、Promise を呪文のように書けるようになることではありません。大切なのは、「非同期処理には成功と失敗の両方がある」「その結果が今すぐにはわからないから、あとで受け取る形にする必要がある」という考え方をつかむことです。そして、その仕組みとして resolve、reject、.then()、.catch() があると理解できれば、次の async/await や fetch() がぐっと学びやすくなります。今回も、初心者向けに、できるだけ順を追って、例題やコードを交えながら丁寧に説明していきます。
まず最初に結論をつかむ
最初に今回の結論をとてもシンプルに言うと、Promise とは「非同期処理の結果をあとで受け取るための箱のような仕組み」です。そして、その箱には次の2つの結果があります。
- 成功したときの結果
- 失敗したときの結果
成功したときは resolve、失敗したときは reject を使います。そして、成功時に続けて行う処理を .then() に、失敗時に行う処理を .catch() に書きます。
初心者の方は、まずこの全体像を頭に入れておくと、そのあとの細かい説明がつながりやすくなります。
Promiseとは何か
Promise とは、非同期処理の最終的な結果を表すオブジェクトです。と言うと少し硬いので、もっとやわらかく言い換えると、「結果がまだ出ていない処理について、あとで成功か失敗かを受け取るための仕組み」です。
たとえば、インターネットからデータを取りに行く処理を考えてみます。その場ですぐ結果が返ってくるとは限りません。通信に少し時間がかかるかもしれませんし、失敗することもあります。そんなとき、「結果が出たら教えてね」という形で受け取る必要があります。その役目をするのが Promise です。
初心者の方は、Promise を「未来の結果が入る予定の箱」と考えるとイメージしやすいです。まだ中身は決まっていないけれど、あとで成功の結果か失敗の理由が入る箱です。
Promiseが必要な理由
ここはとても大切です。なぜ Promise が必要なのかというと、非同期処理では結果が今すぐにはわからないからです。同期処理なら、関数を呼べばその場で結果が返ります。しかし、非同期処理では待ち時間があるため、呼び出した瞬間には結果がまだありません。
たとえば、普通の同期的な関数ならこうです。
// 同期的な関数
function add(a, b) {
return a + b;
}
// すぐに結果が返る
const result = add(2, 3);
console.log(result);JavaScriptこの場合、result にはすぐに 5 が入ります。しかし、非同期処理ではそうはいきません。たとえば2秒後に結果が出るなら、その場ですぐ return しても使えません。そこで Promise を使って、「結果が出たらあとで渡す」という形にする必要があります。
Promiseを日常生活でたとえる
Promise は、日常生活でたとえると「後で結果を知らせる約束」に近いです。たとえば、レストランで料理を注文したとします。注文した瞬間に料理はまだできていません。しかし、店は「できたら持ってきます」と約束してくれます。この「あとで結果を返す約束」が Promise のイメージに近いです。
さらに、その結果には2つの可能性があります。
- 料理が完成して運ばれてくる
- 材料切れなどで提供できないと伝えられる
これが Promise の成功と失敗です。初心者の方は、Promise を「未来の結果を受け取る約束」と考えるとかなり理解しやすくなります。
Promiseの3つの状態
Promise には状態があります。ここは少しだけ大事な基礎知識です。Promise には主に次の3つの状態があります。
- 保留中:まだ結果が決まっていない状態
- 成功:処理がうまくいった状態
- 失敗:処理がうまくいかなかった状態
英語ではよく pending、fulfilled、rejected と呼ばれますが、初心者の段階では無理に英単語を覚えなくても大丈夫です。大切なのは、「まだ結果待ちなのか」「成功なのか」「失敗なのか」という考え方です。
Promise は最初、結果待ちです。そして、どこかのタイミングで成功か失敗のどちらかに決まります。この流れを理解すると、resolve と reject の役割が見えやすくなります。
Promiseの基本形
まずは Promise の書き方の基本形を見てみます。
const promise = new Promise(function (resolve, reject) {
// 非同期処理を書く
});JavaScriptここでの resolve と reject は非常に重要です。
- `resolve` は成功したときに呼ぶ関数です。
- `reject` は失敗したときに呼ぶ関数です。
初心者の方は、この resolve と reject を「成功ボタン」「失敗ボタン」のようなものだと考えるとイメージしやすいです。非同期処理が終わったときに、どちらか一方を押すことで、Promise の結果が決まります。
resolveとは何か
resolve は、Promise の処理が成功したことを伝えるために使います。そして、必要なら成功時の値も渡せます。
たとえば、2秒後に成功メッセージを返す Promise は次のように書けます。
// 2秒後に成功する Promise
const promise = new Promise(function (resolve, reject) {
setTimeout(function () {
// 成功したことを伝える
resolve("データの取得に成功しました。");
}, 2000);
});JavaScriptこのコードでは、2秒後に resolve() が呼ばれます。つまり、「成功しました、その結果はこれです」と Promise に伝えています。
初心者の方は、resolve("値") を「成功の結果としてこの値を渡す」と理解するとよいです。
rejectとは何か
reject は、Promise の処理が失敗したことを伝えるために使います。こちらも必要なら失敗理由を渡せます。
// 2秒後に失敗する Promise
const promise = new Promise(function (resolve, reject) {
setTimeout(function () {
// 失敗したことを伝える
reject("データの取得に失敗しました。");
}, 2000);
});JavaScriptこのコードでは、2秒後に reject() が呼ばれます。つまり、「失敗しました、その理由はこれです」と Promise に伝えています。
初心者の方は、reject("理由") を「失敗したので、この理由を渡す」と考えるとわかりやすいです。
.then() とは何か
resolve で成功した結果は、.then() で受け取ります。.then() は、「成功したらこの処理をしてください」という意味です。
promise.then(function (result) {
console.log(result);
});JavaScriptここでの result には、resolve() に渡した値が入ります。先ほどの成功例と組み合わせるとこうなります。
// 2秒後に成功する Promise
const promise = new Promise(function (resolve, reject) {
setTimeout(function () {
resolve("データの取得に成功しました。");
}, 2000);
});
// 成功したときの処理
promise.then(function (result) {
console.log(result);
});JavaScriptこの場合、2秒後に データの取得に成功しました。 と表示されます。
初心者の方は、.then() を「成功したあとの続きの処理」と覚えると理解しやすいです。
.catch() とは何か
reject で失敗した結果は、.catch() で受け取ります。.catch() は、「失敗したらこの処理をしてください」という意味です。
promise.catch(function (error) {
console.log(error);
});JavaScriptここでの error には、reject() に渡した値が入ります。先ほどの失敗例と組み合わせるとこうなります。
// 2秒後に失敗する Promise
const promise = new Promise(function (resolve, reject) {
setTimeout(function () {
reject("データの取得に失敗しました。");
}, 2000);
});
// 失敗したときの処理
promise.catch(function (error) {
console.log(error);
});JavaScriptこの場合、2秒後に データの取得に失敗しました。 と表示されます。
初心者の方は、.catch() を「失敗したときの受け取り場所」と理解すると整理しやすいです。
成功と失敗をセットで扱う
実際の Promise では、成功だけでなく失敗も考える必要があります。そのため、.then() と .catch() はセットで使うことが多いです。
const promise = new Promise(function (resolve, reject) {
setTimeout(function () {
const isSuccess = true;
if (isSuccess) {
resolve("成功しました。");
} else {
reject("失敗しました。");
}
}, 2000);
});
promise
.then(function (result) {
console.log(result);
})
.catch(function (error) {
console.log(error);
});JavaScriptこのコードでは、isSuccess が true なら成功、false なら失敗になります。初心者の方は、Promise では「成功ルート」と「失敗ルート」の両方を用意するのが基本だと意識するとよいです。
なぜ .catch() が大事なのか
ここは特に深掘りしたい重要ポイントです。初心者の方は、成功パターンだけに意識が向きやすいです。しかし、実際の非同期処理では失敗は普通に起こります。ネットワークエラー、サーバー停止、入力不備、権限不足など、失敗の可能性はたくさんあります。
そのため、.catch() を書かずに成功だけ考えていると、失敗したときに原因がわからなかったり、アプリの状態が不安定になったりします。初心者のうちから、「成功時だけでなく失敗時も設計する」習慣を持つことは非常に大切です。
setTimeout() と Promise を組み合わせて理解する
Day 56では、setTimeout() を使って非同期処理のイメージをつかみました。Day 57では、その setTimeout() を Promise の中で使うと、非同期処理をより整理して扱えることがわかります。
// Promise を返す関数
function waitTwoSeconds() {
return new Promise(function (resolve, reject) {
setTimeout(function () {
resolve("2秒待ちました。");
}, 2000);
});
}
// 結果を受け取る
waitTwoSeconds().then(function (message) {
console.log(message);
});JavaScriptこのコードでは、「2秒待つ処理」が Promise として包まれています。初心者の方は、「Promise は非同期処理を扱いやすくするラッパーのようなもの」と考えると理解しやすいです。
Promiseを関数にする理由
ここで重要なのは、Promise をそのまま1回だけ書くのではなく、関数としてまとめることです。なぜなら、あとで何度も使いたいからです。また、関数にすることで「この関数は非同期で結果を返す」と意味が明確になります。
function getData() {
return new Promise(function (resolve, reject) {
setTimeout(function () {
resolve("データです。");
}, 1000);
});
}JavaScriptこのようにしておくと、getData().then(...) の形で使えます。初心者の方は、Promise を関数の戻り値として返す形に慣れておくと、次のAPI学習でとても役立ちます。
よくあるつまずきポイント
Promise 学習で初心者の方がつまずきやすいポイントを整理しておきます。
- `resolve` と `reject` は今すぐ実行するのではなく、処理が終わったタイミングで呼ぶこと
- `.then()` は成功時だけ、`.catch()` は失敗時だけ動くこと
- Promise は普通の値ではなく、「あとで値が来る約束」であること
- 非同期処理の外側で結果をそのまま使おうとすると混乱しやすいこと
特に最後は大事です。たとえば、Promise の結果を同期処理のようにすぐ使おうとすると失敗しやすいです。初心者の方は、「結果は .then() の中で受け取る」と意識すると整理しやすいです。
そのまま試せるテンプレート
ここでは、Promise の成功と失敗を切り替えて試せる学習テンプレートを紹介します。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Day 57 Promise</title>
</head>
<body>
<h2>Promiseの確認</h2>
<button id="successButton">成功するPromise</button>
<button id="failButton">失敗するPromise</button>
<p id="message">ここに結果が表示されます。</p>
<script>
// 必要な要素を取得する
const successButton = document.getElementById("successButton");
const failButton = document.getElementById("failButton");
const message = document.getElementById("message");
// 成功する Promise を返す関数
function successPromise() {
return new Promise(function (resolve, reject) {
setTimeout(function () {
// 成功した結果を返す
resolve("Promiseが成功しました。");
}, 2000);
});
}
// 失敗する Promise を返す関数
function failPromise() {
return new Promise(function (resolve, reject) {
setTimeout(function () {
// 失敗した理由を返す
reject("Promiseが失敗しました。");
}, 2000);
});
}
// 成功ボタンの処理
successButton.addEventListener("click", function () {
// 処理開始メッセージ
message.textContent = "処理中です...";
// Promise の成功結果を受け取る
successPromise()
.then(function (result) {
message.textContent = result;
})
.catch(function (error) {
message.textContent = error;
});
});
// 失敗ボタンの処理
failButton.addEventListener("click", function () {
// 処理開始メッセージ
message.textContent = "処理中です...";
// Promise の失敗結果を受け取る
failPromise()
.then(function (result) {
message.textContent = result;
})
.catch(function (error) {
message.textContent = error;
});
});
</script>
</body>
</html>
このテンプレートでは、成功と失敗の両方を体験できます。初心者の方は、まずこれを動かして、「成功時は .then() が動く」「失敗時は .catch() が動く」という流れを目で確認すると理解しやすいです。
Promiseが今後どうつながるか
Day 57の Promise は、この先の学習のど真ん中にあります。今後学ぶ fetch() は Promise を返しますし、async/await は Promise をより読みやすく書くための仕組みです。つまり、Promise がわからないまま進むと、その先もわかりにくくなります。逆にここで Promise の基本をしっかり理解できると、API通信や非同期処理のコードがかなり読みやすくなります。
初心者の方は、Promise を単独の文法として覚えるのではなく、「非同期処理の結果の受け取り方」として理解すると定着しやすいです。
初心者が特に注意したいポイント
Day 57では、次の点を特に意識すると理解が深まりやすいです。
- Promise は未来の結果を表す仕組みです。
- `resolve` は成功、`reject` は失敗を表します。
- `.then()` は成功時の処理を書きます。
- `.catch()` は失敗時の処理を書きます。
- 成功だけでなく失敗も必ず考えることが大切です。
- Promise の結果は、その場ですぐ使うのではなく、`.then()` や `.catch()` の中で受け取ります。
特に重要なのは、「Promise = あとで結果が来る」という感覚です。ここがつかめると、非同期処理全体の理解がかなり進みます。
情報セキュリティの観点での注意
Promise 自体は非同期処理の仕組みですが、今後API通信や外部サービス接続に使われることが多くなります。そのため、失敗時の扱いを丁寧に考えることはセキュリティ面でも大切です。たとえば、通信失敗時に正しくエラー処理をしないと、画面が中途半端な状態になったり、意図しない再送信が起きたりすることがあります。初心者の方は、.catch() を単なるおまけではなく、「失敗時の安全策」として見る意識を持つと、堅実な設計につながります。
Day 57のゴールを整理する
Day 57では、次のことができるようになっていれば十分です。
- Promise とは何かを説明できる
- `resolve` と `reject` の役割を説明できる
- `.then()` と `.catch()` の役割を説明できる
- 成功時と失敗時の両方を考えた Promise の基本コードを書ける
- Promise が非同期処理の結果をあとで受け取る仕組みだと理解している
ここまでできれば、Day 57としてはとても順調です。第5フェーズの中心概念がしっかり土台としてできています。
まとめ
Day 57では、第5フェーズ「非同期処理とAPI」の中心テーマとして Promise を学びました。Promise とは、非同期処理の未来の結果を表す仕組みであり、成功したときは resolve、失敗したときは reject を使って結果を決めます。そして、その結果を受け取るために、成功時の処理を .then() に、失敗時の処理を .catch() に書きます。これによって、時間のかかる処理でも、結果が出たあとにどう動くかを整理して書けるようになります。
特に大切なのは、Promise を単なる文法として覚えるのではなく、「非同期処理には成功と失敗があり、その結果はあとで受け取る必要がある」という考え方として理解することです。この感覚がつかめると、今後の fetch() や async/await の学習がかなりわかりやすくなります。
次に進む前に、今回のテンプレートを何度か動かし、resolve を使った場合と reject を使った場合で、どちらが .then() に入り、どちらが .catch() に入るかを自分の言葉で説明できるようにしておくのがおすすめです。ここが自然に言えるようになると、Promise の基本はかなり身についています。
