dart:async はDartにおける非同期プログラミングの中核機能を提供します:Future、Stream。
Future / Streamを利用する際、手動で dart:async をインポートする必要が必ずしもありません。dart:coreからエクスポートされています;StreamController、StreamSubscription、ParallelWaitErrorなどの型を使用する場合は明示的にインポートが必要です:
import 'dart:async';Code language: JavaScript (javascript)
二つの中核概念:
- Future:1回限りの非同期実行結果を表します(将来のいずれかのタイミングで値またはエラーが一度だけ出力される)
- Stream:連続した一連の非同期データを表します(複数の値が次々生成され、イベントストリームに類似)
Future
1. async / await
推奨される記法で、.then()によるチェーン呼び出しより可読性に優れます
asyncを付与した関数はFutureを返却します;awaitはFutureの完了を待機し、結果が返るまで現在のコード実行を一時停止;try-catchで非同期例外を捕捉します。
// async関数はFutureを返す
Future<String> findEntryPoint() async => "main.dart";
Future<int> runExecutable(String entry, List args) async => 0;
Future<void> flushThenExit(int code) async {}
// await記法(推奨)
Future<void> runUsingAsyncAwait() async {
try {
var entryPoint = await findEntryPoint();
var exitCode = await runExecutable(entryPoint, []);
await flushThenExit(exitCode);
} catch (e) {
// 例外を一括捕捉
print("エラー:$e");
}
}Code language: JavaScript (javascript)
2. .then() / .catchError() 従来のチェーン記法
.then():Futureが正常完了した後にコールバックを実行。新しいFutureを返すため連鎖呼び出しが可能.catchError():例外を捕捉;thenの戻り値に連鎖させる必要があります。そうしないとthen内部のエラーを捕捉できません
void runUsingFuture() {
findEntryPoint()
.then((entryPoint) {
return runExecutable(entryPoint, []);
})
.then(flushThenExit)
.catchError((e) {
print("例外:$e");
});
}Code language: JavaScript (javascript)
3. 複数の並列Futureを待機
① Future.wait()
すべてのタスクの完了を待ちます;いずれか一つのFutureがエラーを送出すると全体が即座に失敗します
Future<void> task1() async {}
Future<void> task2() async {}
Future<void> task3() async {}
void testWait() async {
await Future.wait([
task1(),
task2(),
task3(),
]);
print("すべてのタスクが完了しました");
}Code language: JavaScript (javascript)
② List.wait / Record.wait(新機能、並行エラーを詳細に制御)
ParallelWaitError が送出され、成功したタスク・失敗したタスクを個別に判別可能。タスク同士が相互に中断されません。
Future<int> delete() async => 1;
Future<String> copy() async => "ok";
Future<bool> errorTask() async {
throw Exception("タスク失敗");
}
void main() async {
try {
// リスト形式
var results = await [delete(), copy(), errorTask()].wait;
} on ParallelWaitError<List<Object?>, List<AsyncError?>> catch (e) {
print(e.values); // 成功時は値、失敗時はnull
print(e.errors); // 成功時はnull、失敗時はエラー情報を格納
}
// Recordタプル形式:型の異なるFutureに対応
try {
final (resInt, resStr, resBool) = await (delete(), copy(), errorTask()).wait;
} on ParallelWaitError<(int?, String?, bool?), (AsyncError?, AsyncError?, AsyncError?)> catch(e) {
}
}Code language: JavaScript (javascript)
Stream
Stream は連続した一連の非同期データを表します(ファイル1行ごとの読み込み、ボタンクリックイベント、ネットワークデータストリームなど)。
二つの利用方法
1:await for 非同期forループ(簡潔、同期的な走査に近い)
有限のデータストリームに適します;無限に継続するイベントストリーム(画面クリックイベントなど)には不向き。後続コードがブロックされます。
import 'dart:io';
Future<void> readFileByAwaitFor() async {
var file = File("config.txt");
Stream<List<int>> input = file.openRead();
var lines = input
.transform(utf8.decoder)
.transform(const LineSplitter());
try {
await for (final line in lines) {
print("1行読み込み:$line");
}
print("ファイル読み込み完了");
} catch (e) {
print("読み込みエラー $e");
}
}Code language: PHP (php)
2:.listen() 購読監視(無限イベントストリーム向け)
inputStream.listen(
(data) {
// データ受信時のコールバック
},
onError: (err) {
// エラー発生時
},
onDone: () {
// ストリームが正常に終了
},
);Code language: JavaScript (javascript)
listen は
StreamSubscriptionを返し、.cancel()を呼び出すことで購読を解除可能です。
よく使われるStream操作メソッド
- フィルタリング:
where() - 要素取得:
take()、takeWhile() - 要素スキップ:
skip()、skipWhile() - 単一要素取得:
first、last、single、firstWhere()
Streamデータ変換 transform()
トランスフォーマーを介しストリームのデータ型を変更(典型例:バイナリストリームを文字列へ変換)
var lines = inputStream
.transform(utf8.decoder) // List<int> → String
.transform(const LineSplitter()); // String → 1行ごとの文字列Code language: JavaScript (javascript)
listen() と await for 選択指針
- ファイル読み込み、有限シーケンスデータ →
await for - UIイベント、継続配信メッセージなど無限ストリーム →
.listen() - await for は開始後、ストリーム終了まで待機し続けます。無限イベントストリームでは処理が停止します
dart:async ライブラリ
Previous: dart:io