DEV Community

Matheus Ribeiro Miranda
Matheus Ribeiro Miranda

Posted on • Edited on • Originally published at Medium

Funções Assíncronas

Como e quando utilizar: async | future | await | then

Introdução

Quando falamos sobre Flutter não podemos deixar de citar Dart, que é a lingaguem utilizada pelo Framework/UIToolkit, e que assim como outras linguagens também trabalha com funções síncronas e assíncronas que é sobre o que vamos buscar entender aqui.

Explicando os dois tipos de funções

Explicando de uma forma mais grosseira:

Função Síncrona

bool tarefaFinalizada(index) {
   final tarefaFinalizada = tarefas[index].finalizada == true;
   return tarefaFinalizada;
}

Uma função síncrona, assim que chamada, faz com que o sistema aguarde a execução de tudo que estiver dentro dela, para só depois continuar executando o restante das ações.
Podemos entender ela como uma função de certa forma "normal"


Função Assíncrona

Future<List<Tarefas>> getTarefas() async { 
  // Vamos imaginar que o servidor demora 4s para retornar os dados.
   final listaDeTarefas = await http.get('tarefas');
   return listaDeTarefas;
}

Uma função assíncrona, assim que chamada, não é aguardada pelo sitema para que o mesmo de continuidade em seu fluxo, ele apenas continua fazendo o que precisa em paralelo.
Podemos entender ela como uma função que vai ser executada em paralelo com o resto do código sem travar nada e em algum momento no futuro vai retornar algum valor (Ou não).

Uso de algumas palavras-chaves

No caso das funções assíncronas, o Dart faz uso de algumas palavras-chave, que são:

async
Indica que a função vai ser assíncrona e em algum momento, dentro dela, talvez seja preciso esperar para pegar algum dado.


future
Informa que a função vai retornar um dado do futuro, necessário quando utilizamos a palavra-chave async.


Exemplo

Future<Exterminator> getExterminator() async {
  final buscarExterminador = await http.get('exterminator');
  return buscarExterminador;
}

Quando utilizamos funções assíncronas, precisamos utilizar o async e o Future para indicar que aquela função vai retornar um valor no "futuro", como por exemplo: Um retorno do servidor de SUCESSO ou ERRO após 5 segundos.

await
Faz com que o sistema espere naquela determinada linha até o término da função.


then
É uma função anônima (lambda) que só é executada quando a função assíncrona, a qual ela está vinculada, terminar.


Exemplo

Future<void> iniciarSkynet() async { 
   final inicializacaoBemSucedida = await http.put('initialize', data: { "code": 0001 });
   if (inicializacaoBemSucedida) {
     getExterminator().then((Exterminator exterminator){
       exterminator.initializeProtocolZero();
       print("inicializado")
     });
   }
   print("log de inicialização")
}

Utilizamos o await quando fazemos chamadas que retornem um Future e queremos que o sistema espere pelo retorno para que execute o resto das coisas.
Já o then usamos quando fazemos chamadas que retornem um Future, mas não queremos esperar seu resultado e sim executar alguma outra coisa apenas no final, deixando assim o fluxo seguir.

Casos de uso

Vamos entender na prática, quando utilizar cada uma das palavras-chave, utilizando um exemplo de login.

A ideia é que após preenhido os campos (Usuario e senha), a aplicação busque o usuário no servidor e retorne o nome do mesmo, com isso vamos poder saber se o usuário existe para permitir o acesso e caso não exista, podemos preenche-las no primeiro acesso.

Entenda cada expressão da seguinte forma:

  • print(“ ”) como se fosse uma ação visual que está sendo exibida ao usuário em tela.
  • Future.delayed() delays de conexão com o servidor. Apenas para fins didáticos.

// Início do sistema
void main() {

  fazerLoginComFeedback();

}

Future<void> fazerLoginComFeedback() async {

   //Aguarda a função que fará contato com o servidor retornar o nome do usuário
   String nomeUsuario = await getUsuario("matheus", "1234");

   // Verifica se o usuário foi encontrado
   if (nomeUsuario == "") {
     print("Usuário não encontrado!");
   } else {

     //Exibe uma mensagem de boas-vindas com o nome do usuário retornado pelo servidor
     exibirFeedbackVisual(nomeUsuario);

     // Busca os dados do usuário do banco de dados e quando terminar exibe a tela principal
     pegarDados(nomeUsuario).then((dados) { 
       print(dados);

       // Após exibir a mensagem muda para a tela inicial
       print("Abrindo tela inicial.");

     });

   }
}

// Função assíncrona
Future<String> getUsuario(String login, String senha) async {
  print("Buscando usuário...");

  // Requisição ao servidor para saber se o usuário existe
  await Future.delayed(Duration(milliseconds: 2000));

  // Usuário encontrado
  String usuario = "Matheus Ribeiro";

  return usuario;

}

// Função síncrona
void exibirFeedbackVisual(String nomeUsuario) {
  print("Bem vindo, $nomeUsuario");
}

// Função assíncrona
Future<String> pegarDados(String usuario) async {
  print("Buscando dados do $usuario...");

  // Executa algumas consultas no banco para retornar os dados
  await Future.delayed(Duration(milliseconds: 2000));

  // Dados encontrados
  String dadosUsuario = '{"id":1, "email": "usuario@email.com.br"}';

  print("Armazena os dados em memória");

  return dadosUsuario;
}

Enter fullscreen mode Exit fullscreen mode

Como podemos ver, o grande foco do exemplo é o método fazerLoginComFeedback().

Dentro dele podemos ver as diferentes formas de tratar funções assíncronas, utilizando tanto o await quanto o then.

Ambos podem retornar o mesmo resultado, só que necessitam de tratamentos diferentes.

Podemos ver também a chamada da função getUsuario() utilizando o await, pois ali precisamos esperar o resultado da requisição para tomar alguma decisão no processo.

Já a chamada pegarDados() utilizamos o then porque essa função vai apenas buscar os dados no banco de dados e armazenar em memória para serem exibidos na próxima tela (Tela inicial)


FIM

Espero ter conseguido explicar de uma forma clara e objetiva.


Top comments (0)