重要概念#2-3: 非同期プログラミング(Futureとasync/await)

Flutterでネットワーク通信やデータベースアクセスなど、時間のかかる処理を扱う時、必ず「非同期プログラミング」という考え方が必要になります。

このドキュメントでは、Futureasyncawaitという3つのキーワードを中心に、非同期プログラミングの基本を、レストランのウェイターの仕事に例えて解説します。

1. なぜ非同期処理が必要か? - シングルスレッドの問題

Dart(Flutterが使う言語)は、基本的にシングルスレッドで動作します。これは、「一度に一つの作業しかできない」ということです。

もし、すべての処理を「同期的(順番通り)」に行うとどうなるでしょうか?

このウェイターは、キッチンの作業が終わるまで他の仕事を一切できません。その間、お客さんB、C、D...は、注文すらできずにイライラして待つことになります。

Flutterアプリも同じです。もし、重いネットワーク通信(料理)が終わるまでUIの更新(次の注文)をブロックしてしまうと、アプリは完全にフリーズしてしまいます。これではユーザー体験は最悪です。

2. 非同期処理とは「待ち時間を有効活用する」技術

この問題を解決するのが非同期プログラミングです。

このウェイターは、待ち時間を他の作業に充てることで、レストラン全体を効率的に回しています。アプリのUIもフリーズすることなく、サクサク動き続けます。

3. Dartにおける非同期プログラミングの主役たち

Dartでは、この「優秀なウェイターの仕事」を、Futureasyncawaitという3つのキーワードで実現します。

Future - 「未来にもらえる引換券」

Futureは、時間のかかる非同期処理の結果を表すオブジェクトです。

// ネットワークからユーザー名を取得する(かもしれない)関数
Future<String> fetchUserName() {
  // 3秒後に 'Taro' という名前を返す処理をシミュレート
  return Future.delayed(Duration(seconds: 3), () => 'Taro');
}

asyncawait - ウェイターの動きを実現する魔法の言葉

このFuture(引換券)を、簡単かつ直感的に扱うためのシンタックスシュガー(便利な書き方)がasyncawaitです。

コード例

// ユーザー名を取得して、挨拶を表示する関数
Future<void> greetUser() async { // 1. この関数は非同期処理を含む宣言 (async)
  print('ユーザー名を取得します...');

  // 2. fetchUserName()が完了するまで、ここで待つ (await)
  //    でも、アプリはフリーズしない!
  String userName = await fetchUserName();

  // 3. 上のawaitが完了した後、この行が実行される
  print('こんにちは, $userName さん!');
}

void main() {
  greetUser();
  print('greetUser()の呼び出しは完了しました。結果を待っています...');
}

実行結果:

ユーザー名を取得します...
greetUser()の呼び出しは完了しました。結果を待っています...
(3秒後)
こんにちは, Taro さん!

greetUser()を呼び出した後、すぐに次のprint文が実行されていることに注目してください。これが、アプリがフリーズしない証拠です。

非同期プログラミングは、AIとのAPI連携やデータベース操作など、現代のアプリ開発に不可欠なスキルです。この「ウェイターと引換券」のイメージを掴めば、きっとマスターできるはずです。