Promiseの基本
このレッスンで分かること
- Promise は非同期処理の結果 (まだ未確定の値) を表すオブジェクト
- 状態は
pending→fulfilled/rejectedの 3 つ、一度決まると変わらない.then(onFulfilled)/.catch(onRejected)/.finally(onAny)でハンドルasync/awaitは Promise の糖衣構文、現代はそちらが主流
Promiseの基本 とは
Promiseの作成と、then/catch/finallyによるチェーンを練習しよう。本レッスンでは、Promiseの基本 の基本から実際の使いどころまでを整理し、現場で迷わず使える形に落とし込みます。
Promiseの基本
Promiseは非同期処理の結果を表すオブジェクトです。コールバック地獄を解決します。
Promiseの作成
JavaScript
const promise = new Promise((resolve, reject) => {
// 非同期処理
if (成功) resolve(結果);
else reject(エラー);
});then / catch / finally
JavaScript
promise
.then(result => { /* 成功時 */ })
.catch(error => { /* 失敗時 */ })
.finally(() => { /* 常に実行 */ });チェーン
JavaScript
fetchUser(id)
.then(user => fetchPosts(user.id))
.then(posts => console.log(posts))
.catch(err => console.error(err));この問題では、Promiseチェーンの考え方を同期的に練習します。値に対してステップを順番に適用する関数を実装しましょう。
実務で遭遇するパターン
中級レッスンで学んだことが、実際の業務コードでどう登場するかを整理します。
- API 呼び出しの基盤 ─
fetchの戻り値は Promise - 並列処理 ─
Promise.all([p1, p2])で同時待ち、どれかが reject なら全体 reject - 順次処理 ─
.then(...).then(...)のチェーン - タイムアウト実装 ─
Promise.race([fetchPromise, timeoutPromise])
コードレビューで指摘されがちなポイント
PR を出すとシニアから入りやすい指摘です。先回りで身につけておけばレビューが一発で通ります。
new Promise(executor)を不必要に使う ─fetchなどの Promise を直接返せばよい、ラップ不要.catch忘れ ─ 未処理 Promise rejection は Node がプロセスを終了することも- Promise を return し忘れ ─
.thenチェーンで戻り値を return しないと続きが取れない async/awaitで書けるところで.thenチェーン ─ ネストが深いなら書き換え
パフォーマンス考慮事項
- マイクロタスクキュー ─
.thenは次のイベントループより先、setTimeoutより早く走る Promise.allで並列化 ─ 複数の非同期 I/O の待ち時間を重ね合わせるため、順次実行より大幅に短縮できる(待ち時間が完全に重なれば最大で並列数ぶん短くなるが、CPU 処理自体が速くなるわけではない)Promise.raceのリーク ─ 負けた Promise はキャンセルされない (ネットワークコールは続く)- 生成コスト ─ Promise インスタンスは軽量、1 万件 / 秒オーダーなら気にしない
ここまでの要点
Promise は非同期結果を抱える箱、then / catch / finally でハンドル、async/await でフラットに書ける。並列は Promise.all、競争は Promise.race。
よくある質問
Q. Promise と async/await はどっちを使うべき?
A. 新規コードは async/await が圧倒的に読みやすいため第一選択です。Promise.all などで並列実行したいときは Promise メソッドを併用します。最終的に内部では同じ Promise オブジェクトが動いているので、混在しても問題ありません。
Q. rejected の Promise をハンドルしないとどうなりますか?
A. Node.js では UnhandledPromiseRejection の警告が出て、最悪プロセスが落ちます。必ず .catch() を付けるか async 関数内で try/catch で囲んでください。グローバルに process.on('unhandledRejection') で観測する仕組みも入れておくと安心です。
Q. Promise.all と Promise.allSettled の違いは?
A. all は 1 つでも reject すると全体が reject されます。allSettled は全 Promise の結果を {status, value/reason} の配列で返し、失敗があっても他の成功結果は取れます。「全部成功して欲しい」なら all、「個別に結果を集計したい」なら allSettled です。
次のレッスン
次は async/await で、async 関数と await を使って非同期処理を同期的に書く方法を学びます。
事前確認 — 進む前に次の 3 つができることを確認しましょう。
- Promiseの基本 の要点を自分の言葉で説明できる
- このレッスンの最小コード (または操作手順) を見ずに書ける
- 練習問題やクイズで間違えた箇所を読み直して理解した
理解度チェック (30 秒)
Q. Promiseの基本 とは何か、1 文で説明してください。
A. 本文の「このレッスンで分かること」または冒頭の説明文を見直し、自分の言葉で要約できれば OK。詰まったら本レッスンの最初の H2 セクションを読み返してみましょう。
関連レッスン
入出力例
test-cases.txt
processSteps(5, [{"action":"double"},{"action":"add","amount":3}]) → {"error":null,"result":13,"step":null,"success":true}
processSteps(3, [{"action":"subtract","amount":5,"validate":true}]) → {"error":"値が負になりました","result":null,"step":"subtract","success":false}
processSteps(10, [{"action":"subtract","amount":3},{"action":"double"},{"action":"add","amount":1}]) → {"error":null,"result":15,"step":null,"success":true}