投稿者について
2024/09~Flutter開発に携わっているモバイルエンジニアです。
間違っている部分などありましたらご指摘いただけると幸いです。
概念についてざっくり理解する
dartの公式ドキュメント(Asynchronous programming: futures, async, await)を参考にざっくり概念についてまとめてみました。
1. 非同期処理って何だろう
非同期処理 とは端的に言えば 「時間のかかる処理」 を意味します。
逆に 同期処理 というのは 「時間がかからない処理」 を意味します。
(若干乱暴ですが)
公式ドキュメントでは一般的な非同期な処理として以下を挙げています。
- ネットワーク経由でデータを取得
- データベースへの書き込み
- ファイルからデータを読み取り
2. Futureって何だろう
非同期処理を書くためのクラスです。
先ほど、非同期処理は「時間がかかる処理」ということを説明しました。Futureは処理が始まってから終わるまでの結果を表し、未完了または完了の2つの状態を持つことができます。
非同期処理が完了した場合に、以下の3つの結果になります。
- 成功
- 成功して値を返す(
Future<String>
だったらString
の値を返す) - エラー(失敗)
今回は概念の理解をしたいので、エラーの書き方は省略します。
3. asyncって何だろう
非同期関数を定義する際に関数本体の前に配置するものです。
ちなみにasyncだけ付ければ非同期処理自体は正しく実行されます。
つまり、以下2つのコードの違いは戻り値だけになります。
ただ一般的な書き方は2個目の方なので、特に理由がなければ2個目の書き方で書きましょう。
void main() async {
/// 非同期処理
}
Future<void> main() async {
/// 非同期処理
}
4. awaitって何だろう
非同期処理ですが、時間がかかるがゆえに、他の処理と同時並行で実行できます。
でも、一つの非同期処理を終わらせてから他の処理を実行したい場合があります。
その場合に使用するのがawaitです。
awaitは非同期処理(Future<T> () async {}
)が完了するまで次の処理を待機してくれます。
実際に非同期処理を触ってみる
dartの試し書きができるサイトがあるので、実験してみました。
例えば以下のように
1. 3秒後に実行する処理
2. 1秒後に実行する処理
3. 同期処理
という順番でawait
を使用せずに実行しても、出力の順番は、
- 同期処理
- 1秒後に実行する処理
- 3秒後に実行する処理
のようになります。
同期処理・非同期処理両方とも同時に実行されているのが分かりますね。
次に、main関数をFuture<void> main() async {...}
にして、メソッドにawait
をつけてみましょう。
なんと先ほどと同じ順番で出力されました。
- 同期処理
- 1秒後に実行する処理
- 3秒後に実行する処理
await
くん、今の処理が終わるまで次の実行待っててくれる仕組みじゃないんですかね。
では、非同期処理をそれぞれ待ってもらった上で、3秒後に実行→1秒後に実行→非同期じゃない処理の順に行ってもらうにはどうすればいいでしょうか?答えは以下です。
そう、 メソッドの中にもawait
を使用していないと待っていてくれません。
というか、メソッドの中にも実行時にもawaitを使っていないと「順番に処理を終わらせて」くれないみたいです。
↓ main関数内のawaitを削除した場合
すなわち、await
は処理が終わるまで次の処理を待っててくれるが、入れるタイミングを間違えば待っててくれないということになります。
もう少し検証してみましょう。
「非同期メソッドの中に同期メソッドが入っていても順番に処理を行ってくれる」のでしょうか?
1. 3秒後に実行する処理(処理の最後に同期処理「非同期メソッド1が完了しました」)
2. 1秒後に実行する処理(処理の最後に同期処理「非同期メソッド2が完了しました」)
3. 同期処理
出力は以下のようになりました。素晴らしい!期待通りです。
1. 3秒後に実行する処理
2. 非同期メソッド1が完了しました
3. 1秒後に実行する処理
4. 非同期メソッド2が完了しました
5. 同期処理
まとめ
- Dartで非同期処理を書く際は
Future
,async
を使用して処理を書く - 処理が完了するまで他の処理を待機させる場合は
await
を使用する -
await
はちゃんと入れないと待機してくれない