Biblioteca dart:async

A biblioteca dart:async traz os recursos centrais para programação assíncrona em Dart: Future e Stream.

  1. Nem sempre é preciso importar manualmente o dart:async para usar Future / Stream, pois o dart:core já o exporta;
  2. Se você for usar tipos como StreamController, StreamSubscription e ParallelWaitError, é 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 async retornam um Future;
  • await aguarda o término do Future, pausando o código até receber o resultado;
  • Utilize try-catch para 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

  1. Leitura de arquivos, sequências finitas de dados → await for
  2. Eventos de interface, mensagens contínuas e outros fluxos infinitos.listen()
  3. Uma vez iniciado, await for espera até o fluxo terminar; fluxos infinitos causam travamento do código

Biblioteca dart:async

Previous:

Deixe um comentário

O seu endereço de email não será publicado. Campos obrigatórios marcados com *