Dart: Programação Assíncrona no Dart — Future / async-await

Última atualização: 2026-08-26

A programação assíncrona permite que seu programa não espere — uma operação de I/O de 3 segundos deixa a CPU fazer outro trabalho em vez de apenas esperar.

1. O que Você Aprenderá


2. A História Real de um Desenvolvedor

(1) Dor: Requisições Sequenciais Causam Carregamento de 12 Segundos

O DataPipeline do Bob precisa buscar dados de 3 APIs: pedidos (3 segundos), produtos (2 segundos) e clientes (2 segundos). Ele inicialmente usou requisições sequenciais: 3 + 2 + 2 = 7 segundos. Adicionando a consulta ao banco de dados (5 segundos), toda a geração do relatório levou 12 segundos. A experiência do usuário era terrível, e os clientes SaaS reclamavam que era "muito lento."

(2) Solução: Execução Concorrente com Future.wait

Usar Future.wait faz com que as 3 requisições à API rodem concorrentemente, com o tempo total determinado pela mais lenta: 3 segundos. Combinado com consultas concorrentes ao banco de dados, a geração do relatório inteiro é reduzida para 4 segundos.

DART
// Sequencial: 3 + 2 + 2 = 7 segundos
final orders = await fetchOrders();     // 3s
final products = await fetchProducts(); // 2s
final customers = await fetchCustomers(); // 2s

// Concorrente: max(3, 2, 2) = 3 segundos
final results = await Future.wait([
  fetchOrders(),
  fetchProducts(),
  fetchCustomers(),
]);
TEXT 📖 Somente leitura
> **Saída:** Execute no DartPad ou usando `dart run`. Todos os exemplos do curso Dart são baseados no Dart 3.x / Flutter 3.x. Os resultados podem variar ligeiramente dependendo da versão do SDK.

(3) Benefícios


3. Fundamentos do Future

(1) Ciclo de Vida do Future

100%
sequenceDiagram
  participant Bob
  participant API1
  participant API2
  participant API3
  Bob->>API1: fetchOrders()
  Bob->>API2: fetchProducts()
  Bob->>API3: fetchCustomers()
  Note over Bob: Future.wait concorrente
  API1-->>Bob: 1.2M pedidos
  API2-->>Bob: 500K produtos
  API3-->>Bob: 300K clientes
  Bob->>Bob: mesclar & analisar
TEXT 📖 Somente leitura
> **Saída:** Execute no DartPad ou usando `dart run`. Todos os exemplos do curso Dart são baseados no Dart 3.x / Flutter 3.x. Os resultados podem variar ligeiramente dependendo da versão do SDK.

▶ Exemplo

TEXT 📖 Somente leitura
> **Saída:** Execute no DartPad ou usando `dart run`. Todos os exemplos do curso Dart são baseados no Dart 3.x / Flutter 3.x. Os resultados podem variar ligeiramente dependendo da versão do SDK.

: Criando e Usando um Future

DART
import 'dart:async';

// Criar um Future que completa após um atraso
Future<String> fetchOrder() async {
  await Future.delayed(const Duration(seconds: 2));
  return 'ORD-001: \$1500.00 USD';
}

// Future com erro
Future<String> fetchOrderWithRetry() {
  return Future.delayed(const Duration(seconds: 1), () {
    throw Exception('Tempo limite de rede esgotado');
  });
}

void main() async {
  // Pendente → Concluído
  print('Buscando pedido...');
  final order = await fetchOrder();
  print(order);

  // Pendente → Falhou
  try {
    await fetchOrderWithRetry();
  } catch (e) {
    print('Erro: $e');
  }
}
TEXT 📖 Somente leitura
> **Saída:** Execute no DartPad ou usando `dart run`. Todos os exemplos do curso Dart são baseados no Dart 3.x / Flutter 3.x. Os resultados podem variar ligeiramente dependendo da versão do SDK.
Estado do Future Significado
pendente Incompleto, aguardando
concluído com valor Concluído com sucesso, carregando um valor
concluído com erro Concluído com falha, carregando uma exceção

4. async / await em Profundidade

(1) Sintaxe Básica

▶ Exemplo

TEXT 📖 Somente leitura
> **Saída:** Execute no DartPad ou usando `dart run`. Todos os exemplos do curso Dart são baseados no Dart 3.x / Flutter 3.x. Os resultados podem variar ligeiramente dependendo da versão do SDK.

: Fundamentos de async/await

DART
import 'dart:async';

Future<double> calculateOrderTotal(String orderId) async {
  // await pausa a execução até o Future completar
  final amount = await fetchAmount(orderId);
  final taxRate = await fetchTaxRate(orderId);
  return amount * (1 + taxRate);
}

Future<double> fetchAmount(String orderId) async {
  await Future.delayed(const Duration(milliseconds: 500));
  return 1500.0;
}

Future<double> fetchTaxRate(String orderId) async {
  await Future.delayed(const Duration(milliseconds: 300));
  return 0.08;
}

void main() async {
  final total = await calculateOrderTotal('ORD-001');
  print('Total: \$${total.toStringAsFixed(2)} USD');
}
TEXT 📖 Somente leitura
> **Saída:** Execute no DartPad ou usando `dart run`. Todos os exemplos do curso Dart são baseados no Dart 3.x / Flutter 3.x. Os resultados podem variar ligeiramente dependendo da versão do SDK.

(2) Tratamento de Erros

▶ Exemplo

TEXT 📖 Somente leitura
> **Saída:** Execute no DartPad ou usando `dart run`. Todos os exemplos do curso Dart são baseados no Dart 3.x / Flutter 3.x. Os resultados podem variar ligeiramente dependendo da versão do SDK.

: Tratamento de Erros com async/await

DART
import 'dart:async';

Future<String> fetchApiData(String endpoint) async {
  await Future.delayed(const Duration(seconds: 1));
  if (endpoint.contains('invalid')) {
    throw Exception('Erro de API: $endpoint não encontrado');
  }
  return 'Dados de $endpoint';
}

Future<void> robustFetch(String endpoint) async {
  try {
    final data = await fetchApiData(endpoint);
    print('Sucesso: $data');
  } on Exception catch (e) {
    print('Exceção: $e');
  } finally {
    print('Busca concluída para $endpoint');
  }
}

void main() async {
  await robustFetch('orders');           // Sucesso
  await robustFetch('invalid-endpoint'); // Exceção
}
TEXT 📖 Somente leitura
> **Saída:** Execute no DartPad ou usando `dart run`. Todos os exemplos do curso Dart são baseados no Dart 3.x / Flutter 3.x. Os resultados podem variar ligeiramente dependendo da versão do SDK.
Método de Tratamento de Erros Sintaxe Caso de Uso
try-catch try { await f(); } catch (e) {} Quando recuperação é necessária
catchError f().catchError((e) => ...) Estilo funcional
onError f().then(..., onError: ...) Callbacks simples

5. Composição de Futures

(1) Future.wait — Espera Concorrente

▶ Exemplo

TEXT 📖 Somente leitura
> **Saída:** Execute no DartPad ou usando `dart run`. Todos os exemplos do curso Dart são baseados no Dart 3.x / Flutter 3.x. Os resultados podem variar ligeiramente dependendo da versão do SDK.

: Future.wait Concorrente

DART
import 'dart:async';

Future<List<String>> fetchOrders() async {
  await Future.delayed(const Duration(seconds: 3));
  return ['ORD-001', 'ORD-002', 'ORD-003'];
}

Future<List<String>> fetchProducts() async {
  await Future.delayed(const Duration(seconds: 2));
  return ['Laptop', 'Mouse', 'Keyboard'];
}

Future<List<String>> fetchCustomers() async {
  await Future.delayed(const Duration(seconds: 2));
  return ['Alice', 'Bob', 'Charlie'];
}

void main() async {
  // Concorrente: max(3, 2, 2) = ~3 segundos
  final stopwatch = Stopwatch()..start();
  final results = await Future.wait([
    fetchOrders(),
    fetchProducts(),
    fetchCustomers(),
  ]);
  stopwatch.stop();

  print('Pedidos:    ${results[0]}');
  print('Produtos:   ${results[1]}');
  print('Clientes:   ${results[2]}');
  print('Tempo: ${stopwatch.elapsedMilliseconds}ms');
}
TEXT 📖 Somente leitura
> **Saída:** Execute no DartPad ou usando `dart run`. Todos os exemplos do curso Dart são baseados no Dart 3.x / Flutter 3.x. Os resultados podem variar ligeiramente dependendo da versão do SDK.

▶ Exemplo

TEXT 📖 Somente leitura
> **Saída:** Execute no DartPad ou usando `dart run`. Todos os exemplos do curso Dart são baseados no Dart 3.x / Flutter 3.x. Os resultados podem variar ligeiramente dependendo da versão do SDK.

: Tratamento de Erros com Future.wait

DART
import 'dart:async';

Future<String> riskyFetch(String name, bool shouldFail) async {
  await Future.delayed(const Duration(seconds: 1));
  if (shouldFail) throw Exception('$name falhou');
  return 'Dados de $name';
}

void main() async {
  // Future.wait falha rápido - se qualquer um falhar, tudo falha
  try {
    await Future.wait([
      riskyFetch('API-1', false),
      riskyFetch('API-2', true),   // Este vai falhar
      riskyFetch('API-3', false),
    ]);
  } catch (e) {
    print('Future.wait falhou: $e');
  }

  // Preservar resultados individuais com eagerError: false
  final results = await Future.wait(
    [
      riskyFetch('API-1', false).then((v) => Result.success(v)),
      riskyFetch('API-2', true).then((v) => Result.success(v)).catchError((e) => Result.failure(e.toString())),
      riskyFetch('API-3', false).then((v) => Result.success(v)),
    ],
  );

  for (final r in results) {
    print(r.isSuccess ? 'OK: ${r.data}' : 'FALHA: ${r.error}');
  }
}

class Result<T> {
  final T? data;
  final String? error;
  final bool isSuccess;
  Result.success(this.data) : error = null, isSuccess = true;
  Result.failure(this.error) : data = null, isSuccess = false;
}
TEXT 📖 Somente leitura
> **Saída:** Execute no DartPad ou usando `dart run`. Todos os exemplos do curso Dart são baseados no Dart 3.x / Flutter 3.x. Os resultados podem variar ligeiramente dependendo da versão do SDK.

(2) Future.any — Corrida

▶ Exemplo

TEXT 📖 Somente leitura
> **Saída:** Execute no DartPad ou usando `dart run`. Todos os exemplos do curso Dart são baseados no Dart 3.x / Flutter 3.x. Os resultados podem variar ligeiramente dependendo da versão do SDK.

: Future.any Corrida

DART
import 'dart:async';

Future<String> fetchFromCache() async {
  await Future.delayed(const Duration(milliseconds: 100));
  return 'Cache: Dados ORD-001';
}

Future<String> fetchFromApi() async {
  await Future.delayed(const Duration(seconds: 2));
  return 'API: Dados ORD-001';
}

Future<String> fetchFromDb() async {
  await Future.delayed(const Duration(milliseconds: 500));
  return 'DB: Dados ORD-001';
}

void main() async {
  // Retorna o PRIMEIRO a completar
  final fastest = await Future.any([
    fetchFromCache(),
    fetchFromApi(),
    fetchFromDb(),
  ]);
  print('Mais rápido: $fastest');  // Cache: Dados ORD-001
}
TEXT 📖 Somente leitura
> **Saída:** Execute no DartPad ou usando `dart run`. Todos os exemplos do curso Dart são baseados no Dart 3.x / Flutter 3.x. Os resultados podem variar ligeiramente dependendo da versão do SDK.

(3) Future.forEach — Iteração Sequencial

▶ Exemplo

TEXT 📖 Somente leitura
> **Saída:** Execute no DartPad ou usando `dart run`. Todos os exemplos do curso Dart são baseados no Dart 3.x / Flutter 3.x. Os resultados podem variar ligeiramente dependendo da versão do SDK.

: Future.forEach

DART
import 'dart:async';

Future<void> processOrder(String orderId) async {
  await Future.delayed(const Duration(milliseconds: 500));
  print('Processado: $orderId');
}

void main() async {
  final orders = ['ORD-001', 'ORD-002', 'ORD-003'];

  // Processar sequencialmente
  await Future.forEach(orders, processOrder);
  print('Todos os pedidos processados');
}
TEXT 📖 Somente leitura
> **Saída:** Execute no DartPad ou usando `dart run`. Todos os exemplos do curso Dart são baseados no Dart 3.x / Flutter 3.x. Os resultados podem variar ligeiramente dependendo da versão do SDK.
Método de Composição Comportamento Concorrência Caso de Uso
Future.wait Esperar todos Concorrente Requisições em lote
Future.any Primeiro a completar Concorrente Corrida/Fallback
Future.forEach Conclusão sequencial Sequencial Operações dependentes de ordem

6. Controle Manual com Completer

▶ Exemplo

TEXT 📖 Somente leitura
> **Saída:** Execute no DartPad ou usando `dart run`. Todos os exemplos do curso Dart são baseados no Dart 3.x / Flutter 3.x. Os resultados podem variar ligeiramente dependendo da versão do SDK.

: Completer

DART
import 'dart:async';

// Controle manual de Future com Completer
class ApiService {
  final Completer<String> _initCompleter = Completer<String>();

  Future<String> get initialized => _initCompleter.future;

  void onConnected(String serverInfo) {
    if (!_initCompleter.isCompleted) {
      _initCompleter.complete(serverInfo);
    }
  }

  void onError(Object error) {
    if (!_initCompleter.isCompleted) {
      _initCompleter.completeError(error);
    }
  }
}

void main() async {
  final service = ApiService();

  // Simular inicialização assíncrona
  Future.delayed(const Duration(seconds: 1), () {
    service.onConnected('Servidor v3.0.1, 1.000.000 registros');
  });

  print('Aguardando inicialização...');
  final info = await service.initialized;
  print('Conectado: $info');
}
TEXT 📖 Somente leitura
> **Saída:** Execute no DartPad ou usando `dart run`. Todos os exemplos do curso Dart são baseados no Dart 3.x / Flutter 3.x. Os resultados podem variar ligeiramente dependendo da versão do SDK.

7. Cenário do Bob: Requisições Concorrentes à API

▶ Exemplo

TEXT 📖 Somente leitura
> **Saída:** Execute no DartPad ou usando `dart run`. Todos os exemplos do curso Dart são baseados no Dart 3.x / Flutter 3.x. Os resultados podem variar ligeiramente dependendo da versão do SDK.

: Busca Concorrente de Dados no DataPipeline

DART
import 'dart:async';

// Chamadas de API simuladas
Future<List<Map<String, dynamic>>> fetchOrders() async {
  await Future.delayed(const Duration(seconds: 2));
  return [
    {'id': 'ORD-001', 'amount': 1500.0, 'category': 'Electronics'},
    {'id': 'ORD-002', 'amount': 3200.0, 'category': 'Electronics'},
    {'id': 'ORD-003', 'amount': 890.0, 'category': 'Clothing'},
  ];
}

Future<Map<String, double>> fetchProductPrices() async {
  await Future.delayed(const Duration(seconds: 1));
  return {'Laptop': 1299.99, 'Mouse': 29.99, 'Keyboard': 79.99};
}

Future<List<String>> fetchCustomerNames() async {
  await Future.delayed(const Duration(seconds: 1));
  return ['Alice', 'Bob', 'Charlie'];
}

// Busca concorrente de dados com tratamento de erros
Future<void> generateReport() async {
  final stopwatch = Stopwatch()..start();

  try {
    // Buscar todos os dados concorrentemente
    final results = await Future.wait([
      fetchOrders().then((v) => ('orders', v)).catchError((e) => ('orders', null)),
      fetchProductPrices().then((v) => ('products', v)).catchError((e) => ('products', null)),
      fetchCustomerNames().then((v) => ('customers', v)).catchError((e) => ('customers', null)),
    ]);

    stopwatch.stop();

    print('=== Relatório do DataPipeline ===');
    print('Tempo de busca: ${stopwatch.elapsedMilliseconds}ms');

    for (final (key, value) in results) {
      if (value != null) {
        print('$key: OK (${value is List ? value.length : value.length} itens)');
      } else {
        print('$key: FALHOU');
      }
    }
  } catch (e) {
    print('Falha na geração do relatório: $e');
  }
}

void main() async {
  await generateReport();
}
TEXT 📖 Somente leitura
> **Saída:** Execute no DartPad ou usando `dart run`. Todos os exemplos do curso Dart são baseados no Dart 3.x / Flutter 3.x. Os resultados podem variar ligeiramente dependendo da versão do SDK.

8. Exemplo Completo: Processamento Assíncrono de Dados no DataPipeline

DART
// ============================================
// Processamento Assíncrono de Dados do DataPipeline
// Future, async/await e operações concorrentes
// ============================================

import 'dart:async';

// Fontes de dados simuladas
Future<List<Map<String, dynamic>>> fetchOrders({int delay = 2}) async {
  await Future.delayed(Duration(seconds: delay));
  return [
    {'id': 'ORD-001', 'amount': 1500.0, 'status': 'completed', 'category': 'Electronics'},
    {'id': 'ORD-002', 'amount': 50.0, 'status': 'completed', 'category': 'Books'},
    {'id': 'ORD-003', 'amount': 3200.0, 'status': 'pending', 'category': 'Electronics'},
    {'id': 'ORD-004', 'amount': 890.0, 'status': 'completed', 'category': 'Clothing'},
  ];
}

Future<List<Map<String, dynamic>>> fetchProducts({int delay = 1}) async {
  await Future.delayed(Duration(seconds: delay));
  return [
    {'name': 'Laptop', 'price': 1299.99, 'category': 'Electronics'},
    {'name': 'Mouse', 'price': 29.99, 'category': 'Electronics'},
    {'name': 'Novel', 'price': 12.99, 'category': 'Books'},
  ];
}

Future<double> fetchTaxRate(String region) async {
  await Future.delayed(const Duration(milliseconds: 500));
  return switch (region) {
    'US' => 0.08,
    'EU' => 0.20,
    'UK' => 0.15,
    _ => 0.10,
  };
}

// Pipeline assíncrono com operações concorrentes
class AsyncPipeline {
  final String name;
  String status = 'idle';

  AsyncPipeline({required this.name});

  Future<Map<String, dynamic>> run({String region = 'US'}) async {
    status = 'running';
    final stopwatch = Stopwatch()..start();

    try {
      // Passo 1: Busca concorrente de dados
      final (orders, products, taxRate) = await (
        fetchOrders(),
        fetchProducts(),
        fetchTaxRate(region),
      ).wait;

      // Passo 2: Processar pedidos
      final completedOrders = orders
          .where((o) => o['status'] == 'completed')
          .toList();

      // Passo 3: Calcular receita
      final revenue = completedOrders.fold<double>(
        0, (sum, o) => sum + (o['amount'] as double));

      final taxAmount = revenue * taxRate;
      final totalWithTax = revenue + taxAmount;

      // Passo 4: Agrupar por categoria
      final byCategory = <String, double>{};
      for (final order in completedOrders) {
        final cat = order['category'] as String;
        final amt = order['amount'] as double;
        byCategory.update(cat, (v) => v + amt, ifAbsent: () => amt);
      }

      stopwatch.stop();
      status = 'completed';

      return {
        'pipeline': name,
        'region': region,
        'taxRate': taxRate,
        'totalOrders': orders.length,
        'completedOrders': completedOrders.length,
        'revenue': revenue,
        'tax': taxAmount,
        'totalWithTax': totalWithTax,
        'byCategory': byCategory,
        'processingTime': stopwatch.elapsedMilliseconds,
        'status': status,
      };
    } catch (e) {
      status = 'failed';
      rethrow;
    }
  }
}

void main() async {
  final pipeline = AsyncPipeline(name: 'E-Commerce Analytics');

  print('=== Iniciando DataPipeline ===');
  final report = await pipeline.run(region: 'US');

  print('\n=== Relatório ===');
  print('Pipeline:    ${report['pipeline']}');
  print('Região:      ${report['region']}');
  print('Taxa Imposto: ${(report['taxRate'] as double * 100).toStringAsFixed(1)}%');
  print('Total Pedidos: ${report['totalOrders']}');
  print('Concluídos:  ${report['completedOrders']}');
  print('Receita:     \$${(report['revenue'] as double).toStringAsFixed(2)} USD');
  print('Imposto:     \$${(report['tax'] as double).toStringAsFixed(2)} USD');
  print('Total:       \$${(report['totalWithTax'] as double).toStringAsFixed(2)} USD');
  print('Tempo:       ${report['processingTime']}ms');

  print('\nPor Categoria:');
  for (final entry in (report['byCategory'] as Map<String, double>).entries) {
    print('  ${entry.key}: \$${entry.value.toStringAsFixed(2)} USD');
  }
}
TEXT 📖 Somente leitura
> **Saída:** Execute no DartPad ou usando `dart run`. Todos os exemplos do curso Dart são baseados no Dart 3.x / Flutter 3.x. Os resultados podem variar ligeiramente dependendo da versão do SDK.

Saída:

TEXT 📖 Somente leitura
=== Iniciando DataPipeline ===

=== Relatório ===
Pipeline:    E-Commerce Analytics
Região:      US
Taxa Imposto: 8.0%
Total Pedidos: 4
Concluídos:  3
Receita:     $2440.00 USD
Imposto:     $195.20 USD
Total:       $2635.20 USD
Tempo:       2000ms

Por Categoria:
  Electronics: $1500.00 USD
  Books: $50.00 USD
  Clothing: $890.00 USD

❓ Perguntas Frequentes

P: Qual é o tipo de retorno de uma função async? R: Uma função async automaticamente envolve o valor de retorno em um Future. Declare um tipo de retorno Future<T> e simplesmente retorne T dentro da função.

P: await só pode ser usado em funções async? R: Sim. await só pode ser usado em funções async ou geradores async*. Dart 3.5+ suporta await de nível superior (apenas em Dart scripts).

P: O que acontece se um Future falhar em Future.wait? R: Por padrão, se qualquer Future falhar, Future.wait imediatamente lança essa exceção (os outros Futures continuam executando mas seus resultados são ignorados). Você pode usar eagerError: false para esperar que todos completem.

P: Qual é a diferença entre async/await e .then()? R: Eles são funcionalmente equivalentes, mas async/await é mais legível (fluxo linear), enquanto .then() é mais funcional (encadeamento). Para uso diário, async/await é recomendado; .then() é adequado para transformações simples.

P: Quando devo usar Completer? R: Use Completer quando precisar controlar manualmente o momento de conclusão de um Future. Cenários comuns: converter callbacks de eventos em Futures, mensagens WebSocket, callbacks de bibliotecas de terceiros. Na maioria dos casos, você pode simplesmente usar async/await.

P: Future é multicast ou unicast? R: Um Future é unicast — só pode ser consumido por um await ou .then(). Para multicast, você precisa de um Stream ou asStream().

P: Como implementar controle de timeout? R: Use o método Future.timeout(). Por exemplo: await fetchApi().timeout(Duration(seconds: 5), onTimeout: () => defaultData).


📖 Resumo


📝 Exercícios

  1. Básico (Dificuldade ⭐): Escreva 3 funções que retornam Futures (cada uma com um atraso de 1/2/3 segundos). Chame-as sequencialmente usando async/await e meça o tempo total. Depois chame-as concorrentemente usando Future.wait e compare os tempos.
  2. Intermediário (Dificuldade ⭐⭐): Implemente uma função de requisição assíncrona com retry: fetchWithRetry(url, retries: 3, backoff: Duration). Ela deve tentar novamente em caso de falha com backoff exponencial e lançar uma exceção após exceder o limite de retries.
  3. Desafio (Dificuldade ⭐⭐⭐): Implemente um protocolo simples de "requisição-resposta" usando Completer: envie uma requisição e aguarde a resposta correspondente, com suporte a timeout. Simule um barramento de mensagens onde múltiplas requisições podem ser enviadas concorrentemente.

← Lição Anterior | Próxima Lição →

Web-Tutorial.com

Equipe Técnica Web-Tutorial

Uma plataforma de tutoriais mantida por diversos desenvolvedores. Cada tutorial é escrito e revisado por profissionais da área correspondente. Trabalhamos para manter nosso conteúdo preciso e confiável — se encontrar algum problema, avise-nos.

100%