Day 4・非同期とfetchでAPIを叩く
Promiseとasync/await
「あとで返ってくる値」の扱い方を、Promiseとasync/awaitで理解する。
「すぐには返ってこない処理」とは
プログラムには、結果がその場ですぐ出る処理と、少し待たないと結果が出ない処理があります。1+1のような計算は一瞬で終わりますが、外部のサーバーにデータを取りに行く処理は、返事が返ってくるまで数百ミリ秒かかることもあります。この「時間がかかる処理」を、待っている間もプログラム全体を止めずに扱う仕組みを (非同期)と呼びます。
非同期処理の結果を表す入れ物が (プロミス)です。Promiseは「今はまだ値がないけれど、あとで成功か失敗のどちらかで返す」という約束を表す箱だと考えてください。
なぜ非同期が必要なのか
もしサーバーの返事を待つ間プログラム全体が固まってしまうと、その間ボタンも押せず画面も動かなくなります。非同期にすることで、待っている間も他の処理を続けられます。
async/awaitで読みやすく書く
Promiseをそのまま扱うと書き方が入り組みがちです。そこで と await という書き方を使うと、非同期の処理を「上から下に順番に読める」形で書けます。await は「この処理が終わるまで待ってから次に進む」という意味です。
// async をつけた関数の中でだけ await が使える
async function greet(): Promise<string> {
// wait は 1 秒待つだけの Promise を返すと考える
await wait(1000);
return "こんにちは";
}
// 1秒待つ処理を Promise で表した例
function wait(ms: number): Promise<void> {
return new Promise((resolve) => setTimeout(resolve, ms));
}AIにはこう聞く
「この async 関数の戻り値の型は何になりますか? Promise<...> の中身を含めて教えてください」と聞くと、awaitで取り出したあとの本当の型を確認できます。AIが書いたコードでも、型を一緒に確認するクセをつけましょう。
awaitすると中身が取り出せる
awaitを忘れる
const message = greet();
// message は Promise<string> のまま
// 文字列として使おうとすると意図とズレる
console.log(message.length); // 期待した長さにならないawaitで取り出す
const message = await greet();
// message は string になっている
console.log(message.length); // 文字数が取れるasync関数の戻り値は必ずPromiseに包まれます。上の悪い例のように await を忘れると、中身(string)ではなく箱(Promise<string>)のまま扱ってしまい、思った動きになりません。TypeScriptを使っていれば、型が Promise<string> と表示されるので「まだ箱のままだ」と気づけます。
await はどこでも使えるわけではない
await は async をつけた関数の中でしか使えません(トップレベルの一部を除く)。AIが生成したコードで await がエラーになるときは、囲んでいる関数に async が付いているかをまず確認しましょう。
- 非同期 = 時間がかかる処理を、全体を止めずに扱う仕組み
- Promise = あとで成功か失敗で返る値の箱
- async 関数の戻り値は必ず Promise に包まれる
- await でその箱の中身を取り出せる
読んでも腑に落ちない所は、AIに噛み砕いてもらいましょう。
理解度チェック
答えられれば、面接で説明できる状態に一歩近づきます。
async をつけた関数 greet が return "こんにちは"; とだけ書いてあるとき、greet() の戻り値の型は?
await の説明として正しいものは?
非同期処理とPromiseが必要な理由を、初学者にわかるように説明してください。
記述式です。まず自分の言葉で答えを考えてから、模範解答を開いて自己採点してください。