Promise の基本生成 — new Promise((resolve, reject) => {...})
Promiseは「未来のある時点で値が返ることを約束する」オブジェクト。非同期処理の結果と状態を表し、成功・失敗・処理中をわかりやすく扱えます。
概念と状態
- Promiseの役割: 非同期処理の「結果」と「進行状態」を一つのオブジェクトにまとめる仕組み。
- 3つの状態: Pending(処理中)→ Fulfilled(成功)→ Rejected(失敗)。一度FulfilledかRejectedになると、それ以降は変わらない。
基本の作り方と使い方
// 1) Promiseを自分で生成する
const p = new Promise((resolve, reject) => {
// 非同期処理を書く(例: タイマーで疑似非同期)
setTimeout(() => {
const ok = Math.random() > 0.3; // 70%で成功
if (ok) resolve("成功しました");
else reject(new Error("失敗しました"));
}, 500);
});
// 2) 結果の受け取り
p.then(result => {
console.log("結果:", result); // 成功時
}).catch(err => {
console.error("エラー:", err.message); // 失敗時
}).finally(() => {
console.log("必ず呼ばれるクリーンアップ");
});
JavaScript- executor関数:
new Promise((resolve, reject) => {...})の中で非同期処理を行い、成功ならresolve(value)、失敗ならreject(error)を呼ぶ。 - then/catch/finally: 成功時・失敗時・常時実行のハンドラを登録して連鎖できる。
まずは「コールバック地獄」を避ける
従来のコールバックは入れ子が深くなりがち。Promiseは「関数が返すオブジェクトに対してハンドラを登録」する設計で、処理の連鎖とエラーハンドリングがシンプルになります。
// コールバック風(入れ子が増えやすい)
setTimeout(() => {
setTimeout(() => {
console.log("二段目");
}, 500);
}, 500);
// Promise風(直線的につなげる)
new Promise(res => setTimeout(res, 500))
.then(() => new Promise(res => setTimeout(res, 500)))
.then(() => console.log("二段目"));
JavaScriptすぐ使えるテンプレート集
疑似API呼び出しテンプレート
function fetchUser(id) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (id > 0) resolve({ id, name: "Aki" });
else reject(new Error("Invalid id"));
}, 300);
});
}
fetchUser(1)
.then(user => console.log("user:", user))
.catch(err => console.error(err));
JavaScriptチェーンで段階処理(加工→検証→保存)
new Promise(res => res({ id: 1, name: "Aki" }))
.then(u => ({ ...u, name: u.name.toUpperCase() }))
.then(u => {
if (!u.name) throw new Error("No name");
return u;
})
.then(u => console.log("保存:", u))
.catch(err => console.error("失敗:", err.message));
JavaScriptエラーハンドリングのポイント(catchは末尾に)
doTask() // Promiseを返す仮の関数
.then(r => step2(r)) // ここでエラーになればcatchへ
.then(r => step3(r))
.catch(err => {
console.error("どこで失敗してもここで受ける:", err);
})
.finally(() => {
console.log("リソース解放など");
});
JavaScript- エラーはチェーンをショートサーキットして
catchに流れるため、末尾に一箇所置くと見通しが良い。
Promiseの静的メソッド(併用すると便利)
// 即座に成功/失敗のPromiseを作る
Promise.resolve(123).then(v => console.log(v)); // 123
Promise.reject(new Error("x")).catch(e => console.log(e.message)); // x
// 複数の非同期を並行
const p1 = new Promise(res => setTimeout(() => res("A"), 300));
const p2 = new Promise(res => setTimeout(() => res("B"), 200));
Promise.all([p1, p2]) // 全成功で配列が返る、1つでも失敗でreject
.then(([a, b]) => console.log(a, b))
.catch(console.error);
Promise.race([p1, p2]) // 最初に完了した結果だけ得る
.then(v => console.log("race:", v));
Promise.allSettled([p1, p2]) // 成否問わず全結果をまとめる
.then(results => console.log(results));
JavaScript- then/catch/finallyの連鎖や、all/race/allSettled/resolve/reject の活用で表現力が上がる。
async/awaitとの関係(読みやすい糖衣)
async 関数は必ずPromiseを返し、await は「Promiseの結果が来るまで待つ」記法。中身はPromiseだが、直線的な書き味で可読性が高い。
function delay(ms) {
return new Promise(res => setTimeout(res, ms));
}
async function run() {
try {
await delay(300);
const user = await fetchUser(1); // 上で定義した関数を再利用
console.log("取得:", user);
} catch (e) {
console.error("失敗:", e.message);
} finally {
console.log("完了");
}
}
run();
JavaScriptよくある落とし穴と対策
- executorで例外を投げると自動reject: try/catchで包むか、例外はrejectに渡す。
- resolve後にさらにresolve/rejectしても無効: 状態は一度確定したら不変。
- new Promiseの乱用は避ける: 既にPromiseを返すAPIをさらにラップしない(「Promiseコンストラクタアンチパターン」)。
- エラーを飲み込まない: catchを必ずどこかで置く。チェーンの末尾または上位で集約。
練習問題(手を動かして覚える)
// 1) 基本生成と成功・失敗の2パターン
const pOK = new Promise(res => res("OK"));
const pNG = new Promise((_, rej) => rej(new Error("NG")));
pOK.then(console.log);
pNG.catch(e => console.log(e.message));
// 2) チェーンで2倍→文字列化→出力
new Promise(res => res(10))
.then(x => x * 2)
.then(x => String(x))
.then(console.log); // "20"
// 3) 並行処理:3つの遅延どれが最初?
const d = ms => new Promise(res => setTimeout(() => res(ms), ms));
Promise.race([d(300), d(100), d(200)]).then(ms => console.log("最速:", ms));
// 4) async/awaitで例外処理
async function mayFail(ok) {
if (!ok) throw new Error("Oops");
return "done";
}
(async () => {
try {
console.log(await mayFail(true));
console.log(await mayFail(false));
} catch (e) {
console.error("catch:", e.message);
}
})();
JavaScript直感的な指針
- 「非同期の結果を一つのオブジェクトにまとめ、成功・失敗を明示する」のがPromise。
new Promise((resolve, reject) => {...})の中で成功ならresolve、失敗ならreject。受け取りはthen/catch/finallyで連鎖。- 既存のPromiseを返すAPIはそのまま使い、async/awaitで読みやすく書く。
