Promise をつくって返す
このレッスンで分かること
new Promiseに渡した関数の中でresolveを呼ぶと、値が確定します- Promise は戻り値なので、変数に入れたり関数から返したりできます
呼んだ瞬間には、まだ中身が無い
時間のかかる処理を関数にすると、return で答えを返せません。答えが出るのは何百ミリ秒か先で、return の行はもう過ぎているからです。そこで JavaScript は、値の代わりに「あとで値が入る箱」を返す形にそろえました。これが Promise です。
JavaScript
const box = fetchHeadline();
console.log(box); // Promise { <pending> }呼んだ瞬間に返ってくるのは箱だけで、中身はまだ空です。この状態を pending と呼びます。大事なのは、この箱そのものが値だという点です。変数に入れられますし、関数から返せますし、配列に並べることもできます。
箱を自分で作る
自分で箱を作るときは new Promise を使い、引数に関数を 1 つ渡します。この関数はすぐその場で実行され、resolve と reject という 2 つの関数を受け取ります。
JavaScript
function wait(ms) {
return new Promise(function (resolve) {
setTimeout(function () {
resolve("待ち終わりました");
}, ms);
});
}resolve("待ち終わりました") を呼んだ瞬間に、箱の中身が確定します。return の位置に注目してください。返しているのは resolve の結果ではなく、new Promise で作った箱そのものです。箱は関数を呼んだ直後に返り、中身だけがあとから入ります。resolve に渡した値がそのまま中身になり、何も渡さなければ undefined になります。
| 状態 | 意味 | どうなると移るか |
|---|---|---|
| pending | まだ返事が来ていない | 作った直後はこれ |
| fulfilled | 成功の返事が来た | resolve が呼ばれた |
| rejected | 失敗の返事が来た | reject が呼ばれた |
pending から動くのは一度きりです。resolve を 2 回呼んでも、2 回目以降は黙って無視されます。エラーにならないぶん気付きにくいので、確定させる場所は 1 つに絞ってください。今回作る箱は必ず成功する側なので、使うのは resolve だけです。
箱を開ける
箱の中身を外から覗く方法はありません。box.text のように書いても取り出せません。中身に触るには await を書きます。await は async を付けた関数の中でだけ使えます。
JavaScript
async function showHeadline() {
const text = await wait(100);
console.log(text); // 待ち終わりました
}await wait(100) の行で、この関数はいったん中断します。中断しているあいだ作業員は解放されているので、画面は固まりません。中身が確定すると続きから再開し、text に文字列が入ります。await の左の変数に入るのは、箱ではなく中身です。
await が入るより前は、.then に関数を渡して中身を受け取っていました。他人のコードやライブラリの説明で今でもよく見かけるので、対応だけ押さえておきます。
JavaScript
wait(100).then(function (text) {
console.log(text);
});then に渡した関数は、中身が確定したときに、その中身を引数として呼ばれます。自分で書くときは await のほうが読みやすいので、then は読めれば十分です。
もう 1 つ、async を付けた関数の戻り値は必ず Promise になります。中で配列を return しても、呼ぶ側が受け取るのは「あとで配列が入る箱」です。だから呼ぶ側にも await が要ります。
よくある間違い
resolveを呼び忘れる — 箱は pending のまま永遠に確定せず、awaitした側も再開しません。エラーが出ないぶん気付けず、採点では時間切れになります。new Promiseを書いたら、resolveがどの行で呼ばれるかを必ず目で追ってください- 箱のまま使ってしまう —
awaitを書き忘れると、変数に入るのは中身ではなく Promise です。配列やオブジェクトのメソッドが無いというエラーが出たら、まずawaitの書き忘れを疑ってください
要件
- fetchPublishedWorks(works) を作る。new Promise を返し、100 ミリ秒後に published が true の作品だけの配列で resolve する
- loadPublishedTitles(works) を async function として作り、fetchPublishedWorks を await する
- await した結果から title だけを取り出した配列を返す。公開中が 1 件も無ければ空の配列を返す
入出力例
loadPublishedTitles([{"id":1,"published":true,"title":"プロフィールサイト","views":120,"year":2026},{"id":2,"published":true,"title":"自己紹介カード","views":48,"year":2026},{"id":3,"published":true,"title":"スキル一覧の表","views":32,"year":2026},{"id":4,"published":true,"title":"作品ギャラリー","views":76,"year":2026},{"id":5,"published":false,"title":"学習ログ","views":0,"year":2025}]) → ["プロフィールサイト","自己紹介カード","スキル一覧の表","作品ギャラリー"]
loadPublishedTitles([]) → []
loadPublishedTitles([{"id":5,"published":false,"title":"学習ログ","views":0,"year":2025}]) → []
loadPublishedTitles([{"id":1,"published":true,"title":"プロフィールサイト","views":120,"year":2026},{"id":5,"published":false,"title":"学習ログ","views":0,"year":2025}]) → ["プロフィールサイト"]