Promise(プロミス) ぷろみす
非同期処理JavaScriptコールバックasync/awaitイベントループthen/catch
Promiseについて教えて
簡単に言うとこんな感じ!
「今すぐ結果は出ないけど、終わったら必ず知らせるね」という約束の仕組みだよ!レストランで料理を注文したとき、席で待ちながら別のことができるのと同じで、時間がかかる処理を「後で教えてくれるオブジェクト」に任せておける、って感じなんだ!
Promiseとは
Promise(プロミス) とは、JavaScriptをはじめとするプログラミング言語において、非同期処理(すぐに結果が出ない処理)の最終的な完了または失敗を表すオブジェクトのことです。「約束」という英単語の意味どおり、「いつか必ず結果を返す」という契約をプログラム上で表現します。
Webアプリケーションでは、サーバーからデータを取得したり、ファイルを読み書きしたりと、「時間のかかる処理」が頻繁に発生します。Promiseが登場する前は、処理が終わったときに呼び出す関数(コールバック関数)を入れ子にして書く「コールバック地獄」が問題でした。Promiseはこの問題を解消し、非同期処理を直感的に書けるようにした画期的な仕組みです。
現在では、Promiseをさらに使いやすくした async/await 構文の土台としても機能しており、モダンなWeb開発に欠かせない基礎概念となっています。
Promiseの3つの状態
Promiseオブジェクトは必ず次の3つの状態のどれかにあります。一度 fulfilled か rejected になると、状態は変わりません。
| 状態 | 意味 | 例え |
|---|---|---|
| pending(保留中) | 処理がまだ完了していない | 料理を注文中、まだ来ていない |
| fulfilled(解決済み) | 処理が成功して結果が得られた | 料理が届いた! |
| rejected(拒否済み) | 処理が失敗した | 「売り切れでした」と告げられた |
状態遷移のイメージ
pending
(保留中)
/ \
↓ ↓
fulfilled rejected
(成功) (失敗)
覚え方:「ペン・フル・リジェ」
- ペンding → ペンを持って待っている(まだ書けない)
- フルfilled → フルで満たされた(成功!)
- リジェcted → リジェクト(拒否・お断り)
Promiseの基本的な使い方
作る側(Promiseを返す関数)
function fetchData(url) {
return new Promise((resolve, reject) => {
// 時間のかかる処理(例:サーバーへの通信)
setTimeout(() => {
if (url) {
resolve("データ取得成功!"); // 成功 → fulfilled
} else {
reject(new Error("URLがありません")); // 失敗 → rejected
}
}, 1000);
});
}
使う側(.then / .catch でチェーンする)
fetchData("https://example.com/api")
.then((result) => {
console.log(result); // "データ取得成功!"
})
.catch((error) => {
console.error(error); // エラー処理
})
.finally(() => {
console.log("成功・失敗どちらでも実行");
});
async/await で書くと?(より読みやすい書き方)
async function main() {
try {
const result = await fetchData("https://example.com/api");
console.log(result);
} catch (error) {
console.error(error);
}
}
async/await はPromiseを「同期処理のように見える書き方」に変換する糖衣構文(シンタックスシュガー)です。内部では同じPromiseが動いています。
歴史と背景
- 1970年代〜 — 「Future」「Promise」という概念自体は関数型プログラミングの理論として存在していた
- 2011年頃 — jQuery の
$.ajax()に類似したDeferredオブジェクトが普及し、非同期処理の扱いへの関心が高まる - 2012年 — Promises/A+ という仕様がコミュニティ主導で策定され、実装の互換性が担保されるようになる
- 2015年 — ECMAScript 2015(ES6) でJavaScriptの標準仕様として
Promiseが正式採用。bluebirdなどのライブラリが不要になった - 2017年 — ES2017 で
async/await構文が導入。Promiseベースの非同期処理がさらに書きやすくなる - 現在 — Node.js・ブラウザ両方で標準機能として使われ、
fetch APIやWeb Storage APIなど多くのWeb標準APIがPromiseを返す設計になっている
Promiseと関連する非同期処理パターンの比較
非同期処理の書き方は時代とともに進化してきました。同じ処理を3つのスタイルで比べると違いがわかります。
コールバック・Promise・async/await の比較
| スタイル | 登場時期 | 可読性 | エラー処理 | 現在の推奨度 |
|---|---|---|---|---|
| コールバック | 〜2014年 | △ ネスト地獄になりやすい | △ 分散しやすい | ❌ レガシー |
| Promise (.then) | 2015年〜 | ○ チェーンで書ける | ○ .catch で一括 | ○ 現役 |
| async/await | 2017年〜 | ◎ 同期処理のように読める | ◎ try/catchで自然 | ✅ 推奨 |
Promise.all / Promise.race などの便利メソッド
// 複数の非同期処理を並列実行し、全部終わるのを待つ
Promise.all([fetchData("url1"), fetchData("url2")])
.then(([result1, result2]) => {
console.log(result1, result2);
});
// 最初に完了したものだけ使う(競争)
Promise.race([fetchData("url1"), fetchData("url2")])
.then((fastest) => {
console.log("最速:", fastest);
});
Promiseの処理フロー図
関連する規格・RFC
| 規格 | 内容 |
|---|---|
| ECMA-262 (ES2015) | JavaScriptの標準仕様。Promise が §25.4 として正式定義された |
| Promises/A+ | コミュニティが策定したPromise相互運用仕様。ES6 Promiseの基礎となった |
関連用語
- ./030-callback.md — コールバック関数 — 処理完了後に呼び出す関数を引数で渡す旧来の非同期パターン
- ./031-async-await.md — async/await — Promiseをより直感的に書くためのES2017の構文
- ./033-event-loop.md — イベントループ — JavaScriptが非同期処理を管理する仕組み
- ./034-fetch-api.md — Fetch API — HTTPリクエストをPromiseベースで行うブラウザ標準API
- ./035-microtask.md — マイクロタスク — Promiseのコールバックが実行されるタスクキューの種類
- ./036-error-handling.md — エラーハンドリング — try/catchやrejectで例外・エラーを適切に処理する仕組み
- ./029-synchronous-asynchronous.md — 同期・非同期処理 — 処理の完了を待つか待たないかという実行モデルの違い