TypeScriptでasync/awaitをマスター!非同期処理の基本とPromiseの使い方を徹底解説
生徒
「TypeScriptで、通信が終わるのを待ってから次の処理をしたいのですが、どうすればいいですか?」
先生
「それは非同期処理という仕組みを使いますね。TypeScriptでは、asyncとawaitを使うことで、まるで普通の順番通りの処理のように書くことができますよ。」
生徒
「非同期処理って難しそうですが、私にも使いこなせるでしょうか?」
先生
「大丈夫です。基本の書き方さえ覚えれば、とても便利で強力な道具になります。具体的な使い方を一緒に見ていきましょう!」
1. 非同期処理とは何かを身近な例で考えよう
プログラミングの世界には、非同期処理という言葉があります。これは、ある作業が終わるのを待っている間に、別の作業を進めておく仕組みのことです。パソコンを触ったことがない方でも、料理の工程をイメージすると分かりやすいでしょう。
例えば、お湯を沸かしながら野菜を切る場面を想像してください。お湯が沸くのをじっと見つめて、完全に沸騰してから野菜を切り始めるのは効率が悪いですよね。お湯を火にかけたら、その間に野菜を切る。これが非同期処理の考え方です。
TypeScriptなどのプログラミング言語でも、インターネットからデータをダウンロードしたり、大きなファイルを読み込んだりする作業は時間がかかります。その待ち時間を有効活用し、アプリが固まらないようにするために非同期処理が必要になります。
以前のプログラミングでは、この待ち時間を制御するのが非常に大変でしたが、現代のTypeScriptではasyncとawaitという魔法の言葉を使うことで、初心者でも読みやすいコードを書けるようになりました。
2. Promiseという約束の仕組みを理解する
asyncやawaitを学ぶ前に、避けて通れないのがPromise(プロミス)です。日本語に訳すと「約束」という意味になります。
プログラムが何か時間のかかる作業を始めたとき、その作業の代わりに「あとで結果を返しますね」という予約券のようなものを渡してくれます。これがPromiseです。Promiseには三つの状態があります。
- 待機中(Pending):作業を頑張っている最中で、まだ結果が出ていない状態。
- 成功(Fulfilled):無事に作業が終わり、約束通りデータが準備できた状態。
- 失敗(Rejected):何らかのトラブルで作業ができず、約束が守れなかった状態。
このPromiseをより簡単に扱うための仕組みが、今回学習するasyncとawaitなのです。これらを使うことで、「予約券の中身が確定するまで、ここで待機する」という命令を直感的に書けるようになります。
3. async関数の基本的な書き方
まずは、非同期処理を行うための特別な関数を作りましょう。やり方はとても簡単で、関数の前にasyncと付けるだけです。これだけで、その関数は自動的にPromiseを返すようになります。
例えば、挨拶を返すだけのシンプルな関数を作ってみましょう。普通の関数に見えますが、asyncが付くだけで特別な性質を持ちます。
async function sayHello() {
return "こんにちは!";
}
// 実行してみる
sayHello().then(message => {
console.log(message);
});
実行結果は以下のようになります。
こんにちは!
ここで出てきた「.then」という書き方は、Promiseが成功したときに実行される処理です。しかし、この書き方は少し複雑に見えるかもしれません。そこで、次に紹介するawaitが登場します。
4. awaitを使って処理が終わるのを待つ
awaitは「待つ」という意味です。これをasync関数のなかに書くと、非同期な処理が終わるまで、その場所でプログラムを一時停止してくれます。そして、処理が終わると次の行に進みます。
まるで魔法のように、バラバラだった処理の順番が、上から下へと流れるようになります。以下の例では、1秒待ってからメッセージを表示するシミュレーションをしています。
// 擬似的に時間を止める関数
const waitOneSecond = () => new Promise(resolve => setTimeout(resolve, 1000));
async function delayedGreeting() {
console.log("準備中...");
// 1秒待機する
await waitOneSecond();
console.log("1秒経ちました!こんにちは!");
}
delayedGreeting();
実行結果は以下のようになります。最初の文字が出てから、少し遅れて次の文字が表示されます。
準備中...
(1秒後に表示)
1秒経ちました!こんにちは!
awaitを使わないと、待機している間に次の行が先に実行されてしまいますが、awaitのおかげでしっかりと順番を守らせることができます。
5. 実際のデータを取得する流れを見てみよう
プログラミングで非同期処理が最も活躍するのは、インターネット上からデータを取ってくるときです。例えば、ユーザーの情報をサーバーにお願いして受け取るような場合です。
実際の開発では、ネットワークの状況によって、データが届くまでに数秒かかることがあります。その間、アプリが真っ白になったり動かなくなったりするとユーザーは困ってしまいますよね。そこで、データの受信を待ちつつ、画面の他の部分を動かし続けるために非同期処理を使います。
// 擬似的なデータ取得関数
async function fetchUserName(id: number) {
// 本来はここでネットワーク通信を行います
return id === 1 ? "たなか太郎" : "さとう花子";
}
async function showUserProfile() {
console.log("ユーザー情報を探しています...");
// データの到着を待つ
const name = await fetchUserName(1);
console.log("見つかりました!お名前は " + name + " さんです。");
}
showUserProfile();
実行結果は以下の通りです。
ユーザー情報を探しています...
見つかりました!お名前は たなか太郎 さんです。
変数のなかにawaitした結果を入れることで、データの取得が終わった瞬間にその中身を使って、すぐ次の処理に移ることができます。
6. エラーが発生したときの対処法
インターネットの通信は、いつも成功するとは限りません。Wi-Fiが切れていたり、相手のサーバーが故障していたりすることもあります。これをプログラミングでは「エラー」と呼びます。
asyncとawaitを使うときは、try(トライ)とcatch(キャッチ)というブロックを使ってエラーに備えます。「これをやってみて(try)、もしダメだったらこっちで助けて(catch)」という構造です。
async function safeDataFetch() {
try {
console.log("通信を開始します。");
// 何かエラーが起きそうな処理
throw new Error("インターネットがつながっていません!");
const data = await fetchUserName(1);
console.log(data);
} catch (error) {
// エラーが起きたらここに来る
console.log("トラブル発生!内容:" + error.message);
} finally {
console.log("処理を終了しました。");
}
}
safeDataFetch();
実行結果は以下の通りです。
通信を開始します。
トラブル発生!内容:インターネットがつながっていません!
処理を終了しました。
エラーが発生しても、アプリ全体が強制終了することなく、安全にメッセージを出して次のステップへ進めるようになります。これはプロの開発現場でも必須のテクニックです。
7. 複数の非同期処理を同時に行う方法
最後に、少し応用編として「並行処理」を紹介します。これまでは一つずつ順番に待っていましたが、複数のことを同時に進めたほうが早い場合もあります。先ほどの料理の例で言えば、お湯を沸かしながら、電子レンジで冷凍ご飯を温めるようなものです。
TypeScriptでは、Promise.allという機能を使うことで、複数の待機時間を一つにまとめることができます。すべての準備が整うまで待つ、というチームプレーのような仕組みです。
async function parallelTask() {
console.log("複数の作業を同時に開始します。");
const task1 = fetchUserName(1);
const task2 = fetchUserName(2);
// 二つの作業が両方終わるのをまとめて待つ
const results = await Promise.all([task1, task2]);
console.log("一人目:" + results[0]);
console.log("二人目:" + results[1]);
}
parallelTask();
実行結果は以下の通りです。
複数の作業を同時に開始します。
一人目:たなか太郎
二人目:さとう花子
このように書くことで、一つずつ待つよりも劇的に処理速度が向上することがあります。最初は難しく感じるかもしれませんが、まずはasyncとawaitを使って順番通りに動かすことから練習していきましょう。一歩ずつ進めば、必ず自由にプログラミングができるようになりますよ。