A biblioteca dart:async traz os recursos centrais para programação assíncrona em Dart: Future e Stream.
- Nem sempre é preciso importar manualmente o
dart:asyncpara usarFuture / Stream, pois o dart:core já o exporta;- Se você for usar tipos como
StreamController,StreamSubscriptioneParallelWaitError, é necessário realizar a importação explícita:
import 'dart:async';Code language: JavaScript (javascript)
Dois conceitos principais:
- Future: Representa um resultado assíncrono único (produz apenas um valor ou um erro em um momento futuro)
- Stream: Representa uma sequência contínua de dados assíncronos (gera vários valores sucessivamente, parecido com um fluxo de eventos)
Future
1. async / await
Forma preferida, com legibilidade superior às chamadas encadeadas .then()
- Funções marcadas com
asyncretornam um Future; awaitaguarda o término do Future, pausando o código até receber o resultado;- Utilize
try-catchpara capturar exceções assíncronas.
// Funções async retornam Future
Future<String> findEntryPoint() async => "main.dart";
Future<int> runExecutable(String entry, List args) async => 0;
Future<void> flushThenExit(int code) async {}
// Formato com await (recomendado)
Future<void> runUsingAsyncAwait() async {
try {
var entryPoint = await findEntryPoint();
var exitCode = await runExecutable(entryPoint, []);
await flushThenExit(exitCode);
} catch (e) {
// Captura genérica de erros
print("Ocorreu um erro: $e");
}
}Code language: JavaScript (javascript)
2. Formato encadeado tradicional .then() / .catchError()
.then(): Executa um callback quando o Future concluir com sucesso; retorna um novo Future para continuar a cadeia.catchError(): Captura exceções; precisa ser encadeado ao retorno do then, caso contrário não conseguirá capturar erros dentro do then
void runUsingFuture() {
findEntryPoint()
.then((entryPoint) {
return runExecutable(entryPoint, []);
})
.then(flushThenExit)
.catchError((e) {
print("Exceção: $e");
});
}Code language: JavaScript (javascript)
3. Aguardar vários Futures simultâneos
① Future.wait()
Aguarda todas as tarefas finalizarem; se qualquer Future falhar, toda operação falha imediatamente
Future<void> task1() async {}
Future<void> task2() async {}
Future<void> task3() async {}
void testWait() async {
await Future.wait([
task1(),
task2(),
task3(),
]);
print("Todas as tarefas foram concluídas");
}Code language: JavaScript (javascript)
② List.wait / Record.wait (recursos novos, tratamento refinado de erros em concorrência)
Lança ParallelWaitError, possibilita identificar quais tarefas tiveram sucesso e quais falharam, sem que uma interrompa as outras.
Future<int> delete() async => 1;
Future<String> copy() async => "ok";
Future<bool> errorTask() async {
throw Exception("Falha na tarefa");
}
void main() async {
try {
// Formato de lista
var results = await [delete(), copy(), errorTask()].wait;
} on ParallelWaitError<List<Object?>, List<AsyncError?>> catch (e) {
print(e.values); // Valor preenchido se sucesso, null se falhou
print(e.errors); // Null se sucesso, armazena erro se falhou
}
// Formato Record (tupla): aceita Futures de tipos diferentes
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
Um Stream representa uma sequência contínua de dados assíncronos (leitura linha por linha de arquivos, eventos de clique em botões, fluxos de rede).
Duas formas de utilização
1: await for laço assíncrono (sintaxe compacta, parecido com iteração síncrona)
Ideal para fluxos finitos de dados; não serve para fluxos infinitos de eventos (como cliques na interface), pois bloqueia o restante do código.
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("Linha lida: $line");
}
print("Leitura do arquivo finalizada");
} catch (e) {
print("Erro na leitura $e");
}
}Code language: PHP (php)
2 .listen() assinatura de escuta (para fluxos infinitos)
inputStream.listen(
(data) {
// Callback ao receber dados
},
onError: (err) {
// Ocorreu um erro
},
onDone: () {
// O fluxo foi fechado normalmente
},
);Code language: JavaScript (javascript)
O método listen retorna um
StreamSubscription, onde você pode chamar.cancel()para cancelar a assinatura.
Métodos comuns para manipular Stream
- Filtragem:
where() - Limitar itens:
take(),takeWhile() - Ignorar itens:
skip(),skipWhile() - Obter um único elemento:
first,last,single,firstWhere()
Transformação de dados Stream com transform()
Altera o tipo de dados do fluxo usando transformadores (exemplo clássico: converter fluxo binário para texto)
var lines = inputStream
.transform(utf8.decoder) // List<int> → String
.transform(const LineSplitter()); // String → texto linha por linhaCode language: JavaScript (javascript)
Dica de escolha: listen() versus await for
- Leitura de arquivos, sequências finitas de dados →
await for - Eventos de interface, mensagens contínuas e outros fluxos infinitos →
.listen() - Uma vez iniciado, await for espera até o fluxo terminar; fluxos infinitos causam travamento do código
Biblioteca dart:async