Introdução Apresentar algumas diferenças entre funções síncronas e assíncronas. Apresentar as promises , um recurso moderno para encadear operações assíncronas por meio de call-backs aninhados. 2
Execução Síncrona vs Assíncrona Síncrono : cada instrução só inicia quando a anterior termina. Problema : travamentos e falta de responsividade . Assíncrono : tarefas podem ser iniciadas e concluídas em paralelo . Benefícios : melhor experiência do usuário e uso eficiente do tempo.
Funções síncronas vs assíncronas 4 Funções síncronas bloqueiam o fluxo: o navegador parece travar. Funções assíncronas permitem que outras ações continuem acontecendo, melhorando a responsividade. Síncrono é ideal para operações rápidas, como cálculos simples. Já o assíncrono é essencial para operações de rede, acesso a banco de dados e leitura de arquivos
Síncrono vs Assíncrono Síncrono: Faz atividade 1, depois atividade 2, depois atividade 3, ... No nosso exemplo: 40 + 10 + 20 + 5 = 1h e 15minutos para concluir as atividades 6
Síncrono vs Assíncrono Assíncrono: Começa atividade 1, começa atividade 3. Quando acabar atividade 1, faz atividade 2. Quando acabar atividade 3, faz atividade 4 No nosso exemplo: 40 + 10 = 50 minutos para concluir as atividades 7
Funções síncronas vs assíncronas 8 Ao invocar uma função síncrona, o navegador “somente” executará códigos externos à função quando a função for finalizada. Isso pode ser problemático! Por exemplo, em uma página web, se ao clicar em um botão for invocado uma função síncrona, qualquer outra operação só poderá executar quando a função for concluída. Falta de responsividade da página. O navegador vai parecer que “travou” Torna operações independentes atreladas entre si.
Funções síncronas vs assíncronas 9 Considere o trecho de código a seguir: function fazAlgo () { // Realiza alguma operação demorada (1min) ... console . log ( "Fim da função" ); } console . log ( "Começo do processamento" ) fazAlgo (); console . log ( "Fim do processamento" ); Começo do processamento // Depois de um minuto... Fim da função Fim do processamento
Funções síncronas vs assíncronas 10 Já uma função assíncrona, o resultado é... function fazAlgo () { // Realiza alguma operação demorada (1min) ... console . log ( "Fim da função" ); } console . log ( "Começo do processamento" ) fazAlgo (); console . log ( "Fim do processamento" ); Começo do processamento Fim do processamento // Depois de um minuto... Fim da função
Funções síncronas vs assíncronas 11 Já uma função assíncrona, o resultado é... function fazAlgo () { // Realiza alguma operação demorada (1min) ... console . log ( "Fim da função" ); } console . log ( "Começo do processamento" ) fazAlgo (); console . log ( "Fim do processamento" ); Começo do processamento Fim do processamento // Depois de um minuto... Fim da função Considerando que seja uma função assíncrona
Funções síncronas vs assíncronas 12 Vantagens de usar funções assíncronas: Melhor performance: Com funções assíncronas, o programa pode continuar a executar outras tarefas enquanto aguarda a conclusão de uma operação, o que pode melhorar significativamente a performance em determinadas situações. Melhor uso do tempo : Com funções síncronas, o programa fica bloqueado aguardando a conclusão de uma operação, mas com funções assíncronas, o programa pode continuar a executar outras tarefas enquanto aguarda, o que permite que o programa faça melhor uso do tempo. Melhor experiência do usuário: Uma aplicação que usa funções assíncronas pode continuar a responder a interações do usuário enquanto aguarda a conclusão de operações, o que pode melhorar significativamente a experiência do usuário.
Funções síncronas vs assíncronas 13 Vantagens de usar funções assíncronas: Melhor manutenibilidade: Usando funções assíncronas ao invés de callbacks aninhados, o código fica mais fácil de ler e entender. Melhor gerenciamento de erros: Quando se trabalha com funções assíncronas é mais fácil de lidar com erros usando try /catch , ao invés de passar erros para call-backs.
Funções síncronas vs assíncronas 14 O JavaScript é single-threaded: só consegue executar uma instrução por vez. O assíncronismo acontece graças ao Event Loop , que agenda as tarefas demoradas (rede, timers, disco) e libera o fluxo principal para continuar respondendo ao usuário.“ Analogia: "Pense em cozinhar: enquanto o arroz está no fogo, você aproveita para cortar os legumes. Esse paralelismo de tarefas é o que o assíncrono simula no JavaScript."
Encadeamento 15 Um dos detalhes mais importantes do uso de funções assíncronas é o encadeamento de chamadas. Imagine que temos três funções assíncronas (A, B e C) e queremos que B execute depois de acabar A, e que C execute após executar B. Uma possível solução seria...
Encadeamento 16 Um dos detalhes mais importantes do uso de funções assíncronas é o encadeamento de chamadas. Imagine que temos três funções assíncronas (A, B e C) e queremos que B execute depois de acabar A, e que C execute após executar B. Uma possível solução seria... A (); B (); C ();
Encadeamento 17 Um dos detalhes mais importantes do uso de funções assíncronas é o encadeamento de chamadas. Imagine que temos três funções assíncronas (A, B e C) e queremos que B execute depois de acabar A, e que C execute após executar B. Uma possível solução seria... A (); B (); C (); Não funciona! (Mas por quê?)
Encadeamento 18 Uma solução é colocar a chamada da função seguinte no corpo da função anterior. Algo como a seguir... function A () { // Faz função A B (); } function B () { // Faz função B C (); } function C () { // Faz função C } A (); () => { // Faz função A () => { // Faz função B () => { // Faz função C } } } Outra opção, usando arrow function
Encadeamento 19 Uma solução é colocar a chamada da função seguinte no corpo da função anterior. Algo como a seguir... function A () { // Faz função A B (); } function B () { // Faz função B C (); } function C () { // Faz função C } A (); () => { // Faz função A () => { // Faz função B () => { // Faz função C } } } Outra opção, usando arrow function
Encadeamento 20 Uma solução é colocar a chamada da função seguinte no corpo da função anterior. Algo como a seguir... Chamado de “Pirâmide da Desgraça” function A () { // Faz função A B (); } function B () { // Faz função B C (); } function C () { // Faz função C } A (); () => { // Faz função A () => { // Faz função B () => { // Faz função C } } } Outra opção, usando arrow function
Callback Hell Primeira forma de lidar com assincronismo : callbacks. Problema : chamadas aninhadas geram a ' Pirâmide da Desgraça '. Consequências : código difícil de ler e manter , erros complicados . Motivação para surgimento das Promises.
Callback Hell Callback Hell: quando precisamos executar várias operações em ordem, cada função fica dentro da outra, formando a 'Pirâmide da Desgraça'. Isso dificulta leitura, testes e manutenção. O problema não é apenas estético, mas prático: se der erro no meio da cadeia, é muito difícil tratar corretamente.
O que é uma Promise Introduzida no ES2015 para padronizar operações assíncronas. Representa um valor que pode estar disponível agora, no futuro ou nunca. Estados: Pending, Resolved, Rejected. Métodos principais: then(), catch(), finally().
Promises As Promises foram criados em 2015 como forma de padronizar a funcionalidade de funções assíncronas no JavaScript . Anteriormente, bibliotecas externas implementavam a funcionalidade de forma arbitrária. As promises são de fácil manuseio e entendimento, evitando por exemplo o problema da pirâmide da desgraça. 24
Promises 25 Podemos manipular uma promise usando os métodos... then : Contém o que deve ser executado quando o processamento da promise for concluída com sucesso . catch : Contém o que deve ser executado quanto o processamento da promise deu erro. finally : Contém o que deve ser executando quanto o processamento da promise for concluída (sucesso ou erro).
Promises 26 Uma Promise pode estar em três estados diferentes.. Pending : Executando Resolved : Executou com sucesso. Rejected : Executou com erro. Os próprios métodos then e catch retornam promises !
Criando uma Promise Podemos criar Promises com new Promise(). Estrutura : resolve(value) em caso de sucesso , reject(error) em caso de falha . Exemplo : simulação assíncrona com setTimeout . Sucesso/ erro tratados com then() e catch().
Criando uma Promise Característica Callback Promise Legibilidade Baixa (aninhado) Alta (encadeado com .then) Tratamento de erros Complexo Centralizado com .catch Encadeamento Difícil Simples e linear "Promises não eliminam o assíncrono , mas tornam o código mais próximo do estilo sequencial ."
Tratamento de Erros Promises: usar .catch() para capturar exceções . async/await: usar try/catch. Boas práticas : prever falhas de rede, exibir mensagens amigáveis , usar .finally().
Exemplo prático 31 function carregarEnderecoCEP ( cep ) { fetch ( `https://viacep.com.br/ws/ ${ cep } / json /` ) . then (( resposta ) => { return resposta . json (); }) . then (( endereco ) => console . log ( endereco . logradouro )) . catch (( erro ) => console . log ( "Erro na requisição" , erro )) . finally (() => console . log ( "Fim do processamento" )); } carregarEnderecoCEP ( "13565820" ); Consulta a API do ViaCEP para buscar as informações de um dado cep . O retorno do fetch é uma promise !
Exemplo prático 32 function carregarEnderecoCEP ( cep ) { fetch ( `https://viacep.com.br/ws/ ${ cep } / json /` ) . then (( resposta ) => { return resposta . json (); }) . then (( endereco ) => console . log ( endereco . logradouro )) . catch (( erro ) => console . log ( "Erro na requisição" , erro )) . finally (() => console . log ( "Fim do processamento" )); } carregarEnderecoCEP ( "13565820" ); Quando (e se) a resposta for obtida com sucesso, é preciso converter o resultado em JSON recebido (chamado de “resposta”) em um objeto. O comando . json () é uma promise !
Exemplo prático 33 function carregarEnderecoCEP ( cep ) { fetch ( `https://viacep.com.br/ws/ ${ cep } / json /` ) . then (( resposta ) => { return resposta . json (); }) . then (( endereco ) => console . log ( endereco . logradouro )) . catch (( erro ) => console . log ( "Erro na requisição" , erro )) . finally (() => console . log ( "Fim do processamento" )); } carregarEnderecoCEP ( "13565820" ); Depois de convertido em JSON, imprime no console o “logradouro” do CEP encontrado.
Exemplo prático 34 function carregarEnderecoCEP ( cep ) { fetch ( `https://viacep.com.br/ws/ ${ cep } / json /` ) . then (( resposta ) => { return resposta . json (); }) . then (( endereco ) => console . log ( endereco . logradouro )) . catch (( erro ) => console . log ( "Erro na requisição" , erro )) . finally (() => console . log ( "Fim do processamento" )); } carregarEnderecoCEP ( "13565820" ); Caso haja algum problema na requisição ou no processamento, chamará essa função com o “erro” obtido.
Exemplo prático 35 function carregarEnderecoCEP ( cep ) { fetch ( `https://viacep.com.br/ws/ ${ cep } / json /` ) . then (( resposta ) => { return resposta . json (); }) . then (( endereco ) => console . log ( endereco . logradouro )) . catch (( erro ) => console . log ( "Erro na requisição" , erro )) . finally (() => console . log ( "Fim do processamento" )); } carregarEnderecoCEP ( "13565820" ); Independentemente de haver erro ou não, imprime no console a string “Fim do processamento”.
Criando um Promise Além de usar recursos JS que retornam Promises (como a Fetch API!), podemos também criar nossas próprias Promises . Uma promessa é um objeto que tem um método com dois parâmetros, o resolve e o reject . Veja o exemplo a seguir: 36
Criando um Promise 37 const promessa = new Promise (( resolve , reject ) => { // Implemente aqui o que deseja executa de forma assíncrona let success = true ; if ( success ) { // Usado para indicar que a operação finalizou com sucesso resolve ( "OK" ); } else { // Usado para indicar que a operação finalizou com erro! reject ( "Falha" ); } });
Promise.all Imagine que você pediu três pizzas em restaurantes diferentes. Você só pode começar a festa quando TODAS chegarem. Se uma delas atrasar ou for cancelada, a festa não acontece. ➡ Isso é o Promise.all. 39
Promise.all Recebe um array de Promises. Executa todas em paralelo. Retorna quando todas terminarem com sucesso → array de resultados. Se uma só falhar, tudo é rejeitado e você vai para o catch. 40
Promise.all Montamos várias Promises (cada uma é uma entrega). Jogamos dentro do Promise.all([...]). O JavaScript espera todas terminarem. Se todas derem certo → retorna array. Se uma der errado → cai direto no catch. 42
Promise.all Buscar dados de vários usuários antes de montar a tela. Carregar vários arquivos ou imagens antes de liberar a página. Fazer várias requisições em paralelo para economizar tempo. 43
Promise.race Imagine uma corrida de cavalos. Não importa quem são os competidores, você só quer saber quem chega primeiro. ➡ Isso é o Promise.race. 44
Promise.race Imagine uma corrida de cavalos. Não importa quem são os competidores, você só quer saber quem chega primeiro. ➡ Isso é o Promise.race. 45
Promise.race Como funciona: Recebe um array de Promises. Retorna o primeiro resultado (seja sucesso ou erro). Não cancela os outros — eles continuam correndo, mas são ignorados. 46
Promise.race Criamos uma Promise timeout que falha depois de X segundos. Colocamos a busca real (fetch) e o timeout dentro de Promise.race. Se a API responder rápido → fetch vence. Se demorar muito → timeout vence → erro de tempo. Isso protege a aplicação contra esperas infinitas. 47
Promise.race Definir um tempo máximo de resposta para uma API. Buscar dados de várias fontes e usar a primeira que responder. Melhorar a experiência do usuário, evitando travamento ou loading eterno. 48
Promise.all vs Promise.race 49 Recurso Quando usar Promise.all Preciso de todos os resultados antes de continuar. Se um falhar, todo o processo falha. Promise.race Quero o primeiro resultado possível (sucesso ou falha). Uso típico: timeout ou fallback rápido.
async e await Como forma de facilitar o desenvolvimento e manutenção, a versão do JS ES2017 criou duas palavras-chave: async e await . O async e await são formas de codificar funções assíncronas de forma muito similar a codificação de funções síncronas “normais”. Por baixo dos panos, continuam sendo promises . 50
51 O que é async? É uma palavra-chave que você coloca antes de uma função . Isso transforma a função em uma função assíncrona . Toda função async retorna uma Promise, mesmo que você não perceba . async function exemplo () { return 42; } exemplo ().then(x => console.log(x)); // imprime 42
52 O que é await? É uma palavra-chave que só pode ser usada dentro de funções async. Ela pausa a execução da função até que a Promise seja resolvida ou rejeitada . Parece que o código fica “ síncrono ”, mas não trava o JavaScript inteiro , apenas aquela função .
Exemplo de async e await function promessaDeTeste () { return new Promise(resolve => { setTimeout (() => resolve("OK depois de 2s"), 2000); }); } async function rodar () { console.log("Início"); let resultado = await promessaDeTeste (); // espera 2 segundos console.log( resultado ); console.log("Fim"); } rodar (); 53 Início ... (2 segundos ) ... OK depois de 2s Fim
Async/Await 54 async function obterNome () { let data = await fetch ( "..." ); data = await data . json (); return data . nome ; } obterNome (). then (( resposta ) => { console . log ( `Nome: ${ resposta } ` ); })
Async/Await 55 Uma função assíncrona (que possua await dentro dela) deve ser declarada como async . async function obterNome () { let data = await fetch ( "..." ); data = await data . json (); return data . nome ; } obterNome (). then (( resposta ) => { console . log ( `Nome: ${ resposta } ` ); })
Async/Await 56 O await retorna o resultado após a conclusão do Promise . async function obterNome () { let data = await fetch ( "..." ); data = await data . json (); return data . nome ; } obterNome (). then (( resposta ) => { console . log ( `Nome: ${ resposta } ` ); })
Async/Await 57 O retorno não deve ter await async function obterNome () { let data = await fetch ( "..." ); data = await data . json (); return data . nome ; } obterNome (). then (( resposta ) => { console . log ( `Nome: ${ resposta } ` ); })
Async/Await 58 Após o processamento da função obterNome (), o valor obtido será impresso no console. Atenção! Na main , o comando await não deve ser utilizado. async function obterNome () { let data = await fetch ( "..." ); data = await data . json (); return data . nome ; } obterNome (). then (( resposta ) => { console . log ( `Nome: ${ resposta } ` ); })
Async/Await 59 Como construir funções com async/await : Coloque async na frente da função . Use await sempre que precisar do resultado de uma Promise. Use try/catch para capturar erros .
Async/Await async function buscarCEP (cep) { try { let resposta = await fetch(`https://viacep.com.br/ ws /${cep}/ json /`); let dados = await resposta.json (); if ( dados.erro ) throw new Error("CEP inválido "); console.log( dados.logradouro ); } catch ( erro ) { console.log("Erro:", erro.message ); } } 60 ➡ Vantagem : código fica linear e legível , sem precisar de vários .then() .
Tratamento de erros... 61 async function obterNome () { try { let data = await fetch ( "..." ); if (! data . ok ) { throw new Error ( "..." ); } data = await data . json (); return data . nome ; } catch ( error ) { console . log ( "Houve erro em... " . error ); throw error ; } } obterNome () . then ( data => { ... }) . catch ( error => { console . log ( "Erro: " , error ); })
Considerações finais Promises são usadas para tratar de funções assíncronas. Se você pretende desenvolver programas multithread , pesquise por Web Workers . Promises são extensamente usadas em frameworks e bibliotecas recentes de desenvolvimento web, como React , Angular, Node e similares. 62
Comparando Promise x Async/Await 63 fetch("https://viacep.com.br/ ws /13565820/ json /") .then(r => r.json ()) .then(d => console.log( d.logradouro )) .catch(e => console.log("Erro:", e.message )); async function exemplo () { try { let r = await fetch("https://viacep.com.br/ ws /13565820/ json /"); let d = await r.json (); console.log( d.logradouro ); } catch (e) { console.log("Erro:", e.message ); } }
Comparando Promise x Async/Await 64 Promise = você pede uma pizza. Ela promete chegar . Você combina com o entregador (then) ou trata erro (catch). async/await = você pede a pizza e espera sentado até ela chegar . Enquanto isso , a cozinha (JavaScript) continua funcionando , só sua função está “ pausada ”.
Comparando Promise x Async/Await 65 async: transforma uma função em assíncrona → retorna sempre uma Promise. await: pausa dentro da função async até a Promise terminar ( sucesso ou erro ). try/catch: captura erros dentro do fluxo assíncrono . Serve para deixar o código assíncrono com cara de síncrono , mais fácil de ler e manter .
Exercicios 67 1) Escreva uma função que faz um console.log("Início"), aguarda 3 segundos com setTimeout e depois imprime "Fim". Pergunta : Qual linha aparece primeiro no console? Por quê ? Como usar o setTimeout via arrow function: setTimeout (() => {}, tempoemmilisegundos );
Exercicios 68 2) Crie uma Promise que sempre retorna "Olá, mundo !" após 2 segundos . Teste com .then() para imprimir o resultado . 3) Crie uma Promise que pode terminar em sucesso ou falha (use Math.random() > 0.5). Se sucesso → resolva com "Sucesso!". Se falha → rejeite com "Erro!". Trate os dois casos com .then() e .catch().
Exercicios 4)Encadeamento de Promises Crie três funções: A(), B(), C(). A resolve após 1s com "A pronto". B resolve após 1s com "B pronto". C resolve após 1s com "C pronto". Encadeie A().then(B).then(C) para que rodem em sequência. Pergunta: E se chamar A(); B(); C(); direto, o que acontece? 69
Exercicios 5) Crie 3 Promises que resolvem em tempos diferentes (1s, 2s, 3s). Use Promise.all() para esperar todas terminarem e mostrar os resultados juntos. Pergunta: E se uma falhar, o que acontece? 70
Exercicios 6) Use Promise.race() com 3 Promises de tempos diferentes. Mostre quem retorna primeiro. Pergunta: Para que situações reais isso seria útil? 71
Exercicios 7) Crie uma Promise que pode falhar. Encadeie 3 .then() e mostre como o erro é capturado só no .catch() final. Pergunta: Por que é mais simples tratar erros em Promises do que em callbacks? 72
Exercicios 8) Simule 2 chamadas: carregarUsuario() → demora 2s. carregarPosts() → demora 3s. Use Promise.all() para só mostrar "Tela carregada" quando ambas terminarem. Pergunta: Qual vantagem de carregar em paralelo em vez de sequência? 73
Exercicios 9) Crie uma função que mostra "Carregando..." no console. Use setTimeout com 5s para resolver uma Promise e imprimir "Dados carregados!". Mostre como usar .finally() para sempre remover a mensagem "Carregando...". 74