Programação assíncrona básica
A Programação assíncrona é uma forma de executar tarefas que podem demorar sem travar o restante do programa. Algumas operações não retornam o resultado imediatamente, por exemplo:
- ler um arquivo grande
- consultar um banco de dados
- fazer uma requisição HTTP
- esperar uma resposta de API
- salvar dados em disco
- buscar informações em um servidor
No Dart, essas operações normalmente usam:
- Future
- async
- await
Código síncrono
Antes de entender o assíncrono, veja um exemplo de código síncrono:
void main() {
print('Iniciando sistema');
print('Carregando usuários');
print('Sistema finalizado');
}
Esse código executa linha por linha, se alguma linha precisar receber um dado, o processo para e espera até que esse dado seja fornecido. Isso é execução síncrona.
Problema com tarefas demoradas
Imagine que carregar usuários demore alguns segundos.
void main() {
print('Iniciando sistema');
print('Buscando usuários no banco de dados...');
print('Sistema finalizado');
}
Em um programa real, buscar usuários em banco pode demorar. O programa precisa esperar a resposta antes de continuar usando aqueles dados. É nesse tipo de situação que entra programação assíncrona.
O que é Future
Um Future representa um valor que vai existir no futuro. Uma função que demora para responder pode retornar um Future.
Future<String> buscarUsuario() {
return Future.value('Fulano');
}
A função acima não retorna diretamente uma String. Ela retorna: Future<String>, ou seja, essa função vai entregar uma String no futuro. Comparando com Python, é parecido com uma função async que precisa ser aguardada com await.
Criando um Future com atraso
Podemos simular uma tarefa demorada usando Future.delayed.
Future<String> buscarUsuario() {
return Future.delayed(Duration(seconds: 2), () {
return 'Fulano';
});
}
void main() {
print('Iniciando busca');
buscarUsuario();
print('Fim do programa');
}
A função buscarUsuario() demora 2 segundos para retornar 'Fulano'. Mas nesse exemplo, o main() não espera o resultado. O resultaod desse código é:
Iniciando busca
Fim do programa
O valor 'Fulano' não aparece, porque chamamos a função, mas não aguardamos o resultado.
Usando async e await
Para esperar o resultado de um Future, usamos await. Mas para usar await, a função precisa ser marcada com async.
Future<String> buscarUsuario() {
return Future.delayed(Duration(seconds: 2), () {
return 'Fulano';
});
}
Future<void> main() async {
print('Iniciando busca');
String usuario = await buscarUsuario();
print('Usuário encontrado: $usuario');
print('Fim do programa');
}
O resultaod desse código é:
Iniciando busca
Usuário encontrado: Fulano
Fim do programa
A linha abaixo espera o resultado da função:
String usuario = await buscarUsuario();
Como buscarUsuario() retorna um Future<String>, o await espera esse Future terminar e pega a String final. Sem await, você tem uma promessa de resultado, mas com await, você espera o resultado real.
O que significa async
O async informa que uma função trabalha com código assíncrono.
Future<void> main() async {
// código assíncrono aqui
}
Quando uma função usa async, ela passa a retornar um Future. Por isso o main() ficou assim:
Future<void> main() async {
O void significa que a função não retorna valor, já o Future<void> significa que essa função é assíncrona, ou seja, ela não retorna um valor útil, mas pode demorar para terminar
Future com retorno
Quando uma função assíncrona retorna um valor, o tipo fica assim:
Future<String>
Future<int>
Future<double>
Future<Usuario>
Future<List<Usuario>>
Bem básico essa parte, mas resolvi mostrar porque no começo tudo parece ser bem complicado (até mesmo para mim).