【Flutter】非同期プログラミング：futures, async, await

# はじめに
今まで何となくで使ってきていたのでしっかり確認しようと思い、以下を読んで個人的にまとめていきます。

https://dart.dev/codelabs/async-await

## この記事を通して分かること

- いつどのようにasync/awaitを使うか
- 実行順序にどのような影響があるか

# 非同期コードが重要な理由
非同期処理をすると、他の処理の終了を待っている間に処理を完了出来ます。

- 同期処理
    - 完了するまで他の処理をブロックする
    - 同期関数は、同期処理のみ実行
- 非同期処理
    - 開始したら、それが完了する前に他の処理を実行できる
    - 非同期関数は少なくとも1つの非同期処理を実行し、同期処理も実行可能

## 非同期処理を使う一般的なもの
- ネットからデータを取得する
- データベースに書き込む
- ファイルからデータを読み込む

Dartでは非同期処理を行うときにFutureクラスとasync/awaitを使用します。

## futureとは？

- futureはFutureクラスのインスタンスで2つの状態を持つ
    - 未完了（Uncompleted）
        - 非同期処理を呼び出したとき、未完了のfutureを返す
        - このfutureは非同期処理の完了を待つか、エラーを出す
    - 完了（Completed）
        - 非同期処理が成功すれば、futureは値（もしくはエラー）を持って完了する
- `Future<T>`のインスタンスはT型の値を作る
    - 例えば`Future<String>`であればString型の値を作る
    - もし値を持たないのであれば、`Future<void>`を使う

## async/awaitとは？
非同期処理に使います。

### 基本的なガイドライン

- 非同期関数を定義するためには、関数本体の前にasyncを追加する
- awaitはasync関数の中でだけ使えるキーワード

### 実行の流れ
async関数は初めのawaitキーワードにたどり着くまでに、その間にある同期処理を実行します。つまり、await前にある全ての同期コードは即座に実行されます。

awaitの処理が終わるまで、それ以降のコードは実行されません。

# 同期処理と非同期処理

実際にコードを使って同期処理と非同期処理を確かめていきます。

## 同期処理
以下のコードは間違っています。後ほどasync/awaitで直しますが、どこが問題でしょうか？

```dart
String createOrderMessage() {
  var order = fetchUserOrder();
  return 'Your order is: $order';
}

Future<String> fetchUserOrder() =>
    Future.delayed(
      const Duration(seconds: 2),
      () => 'Large Latte',
    );

void main() {
  print(createOrderMessage());
}
```

```
Your order is: Instance of '_Future<String>'
```

本当は**Your order is: Large Latte**になって欲しかったのですが、createOrderMessage()がfetchUserOrder()の終了を待たずに出力してしまっています。

## 非同期処理
上記のコードをasync/awaitを使えば適切に処理できます。

```dart
// Future<String>に変更！
Future<String> createOrderMessage() async { // async追加！
  var order = await fetchUserOrder();       // await追加！
  return 'Your order is: $order';
}

Future<String> fetchUserOrder() =>
    Future.delayed(
      const Duration(seconds: 2),
      () => 'Large Latte',
    );

Future<void> main() async {          // async追加！
  print('Fetching user order...');
  print(await createOrderMessage()); // await追加！
}
```

```
Fetching user order...
Your order is: Large Latte
```
createOrderMessage()はfetchUserOrder()が終了するまで次の処理に進んでいないため、上手く処理されています。


# その他の例
実行順序に関する例をもう一つ載せます。それぞれどのように出力されるか考えてみましょう。

## コード

```dart:パターン1
Future<void> printOrderMessage() async {
  print('Awaiting user order...');
  var order = await fetchUserOrder();
  print('Your order is: $order');
}

Future<String> fetchUserOrder() {
  return Future.delayed(const Duration(seconds: 4), () => 'Large Latte');
}

Future<void> main() async {
  countSeconds(4);
  await printOrderMessage();
}

void countSeconds(int s) {
  for (var i = 1; i <= s; i++) {
    Future.delayed(Duration(seconds: i), () => print(i));
  }
}
```
```dart:パターン2
Future<void> printOrderMessage() async {
  var order = await fetchUserOrder(); // 順序を入れ替えた
  print('Awaiting user order...');    // 順序を入れ替えた
  print('Your order is: $order');
}

Future<String> fetchUserOrder() {
  return Future.delayed(const Duration(seconds: 4), () => 'Large Latte');
}

Future<void> main() async {
  countSeconds(4);
  await printOrderMessage();
}

void countSeconds(int s) {
  for (var i = 1; i <= s; i++) {
    Future.delayed(Duration(seconds: i), () => print(i));
  }
}
```

## 出力結果
```:パターン1
Awaiting user order...
1
2
3
4
Your order is: Large Latte
```

```:パターン2
1
2
3
4
Awaiting user order...
Your order is: Large Latte
```

# おわりに
ざっくりとしたイメージは「awaitの部分で一旦止めてその処理が終わるまで次には進まない」感じですかね。今回の内容やコードは以下のものを使用させていただきました。

https://dart.dev/codelabs/async-await

ここまで読んでいただきありがとうございました。何かありましたらコメントをお願いします。