App Masters

App Masters

  • English
  • Português

›Fundamentos de Javascript

App Masters - Core

  • Início
  • Conteúdo

Backend

  • Adonis
  • Laravel
  • Livewire
  • Sequelize

Fundamentos de Javascript

  • Javascript Assíncrono
  • Typescript

Padrões de Projeto

  • Presentational Container Design Pattern

Frontend

  • Ant Design
  • Flexbox
  • Media Queries
  • React Hook Form
  • Redux
  • Redux-Saga
  • Redux-Thunk
  • Styled Components
  • Tailwind
  • TWA
  • Yup

Testes

  • Cypress
  • Detox
  • Jest

Ferramentas

  • Docker
  • nvm
  • Storybook
  • Visual Studio Code

CMS

  • Strapi

Javascript Assíncrono

O que é?

Um código é assíncrono quando implementa uma função que começa agora e termina depois, e não espera pelo resultado dessa função. Normalmente, o código é síncrono: isso significa que cada instrução tem que esperar a última ser concluída antes de prosseguir.

Exemplo de código síncrono

console.log(1)
console.log(2)
console.log(3)
console.log(4)

O que esse código imprime é:

1
2
3
4

Podemos ver que o output segue a mesma ordem do que escrevemos no exemplo..

Exemplo de código assíncrono

console.log(1)
console.log(2)

setTimeout(() => {
    console.log('callback');
}, 2000);


console.log(3)
console.log(4)

O output do console é:

1
2
3
4
callback

Diferentemente do que esperávamos, o programa não espera o retorno do timeout para printar callback. Ele continua o fluxo de execução do programa até receber a resposta da função callback, e então, printar.

Callback

O retorno de chamada é uma função disparada quando e se você obtiver o resultado de retorno. No exemplo abaixo, a função de retorno de chamada é acionada após 2 segundos, portanto, é acionada quando expirou o tempo limite (não se, não para de contar, exceto se você fechar a página do navegador ou se o mundo parar) :

setTimeout(() => {
    console.log('callback');
}, 2000);

Callback Hell

E se você quiser definir diferentes tempos limite para cada saída? Não sei por que você faria isso, mas você pode pensar em um código como este:

setTimeout(() => {
    console.log(1);
}, 3000);

setTimeout(() => {
    console.log(2);
}, 2000);

setTimeout(() => {
    console.log(3);
}, 1000);

O output seria:

3
2
1

Não! Mas não é o que você queria. Você deseja que ele espere 3 segundos e depois exiba 1, espere 2 segundos e depois exiba 2 e, finalmente, espere 1 segundo e exiba 3. Para fazer isso, você precisa aninhar os retornos de chamada:

setTimeout(() => {
    console.log(1);
    setTimeout(() => {
        console.log(2);
        setTimeout(() => {
            console.log(3);
        }, 1000);
    }, 2000);
}, 3000);

Para esse código, o output é como as expectativas:

1
2
3

Mas eu espero que vc concorde que esse código é muito difícil de ler e entender. É por isso que esses callbacks aninhados são chamados de callback hell.

Promises

Uma Promise é uma promessa de que algo que você pediu vai acontecer. Isso significa que você não tem certeza se uma tarefa vai ser concluída ou não. Note que o conceito original e o conceito em javascript são muito parecidos.

Vamos criar uma situação:

Você é um programador (e se você está aqui, eu aposto que é isso mesmo), e você não sabe Promises. Eu estou te prometendo que você vai entender assim que terminar de ler.

Isso é uma promessa, e tem 3 estados:

  1. Pendente: Você não sabe se você vai aprender Promises
  2. Realizada: Eu estou orgulhosa de você e eu vou te dar um biscoito
  3. Rejeitada: Eu só menti

Escrevendo isso em Javascript:

let mentirosa = true;

let vaiAprenderPromises = new Promise(
    (resolve, reject) => {
        if(mentirosa){
            let motivo = new Error('sim, eu menti');
            reject(motivo);
        }else{
            let biscoito = "Estou te dando um biscoito!";
            resolve(biscoito)
        }
    }
)

Eu acredito que esse código seja bem simples de entender. Mas, como formalidade, vou explicar a estrutura de uma Promise.

Uma Promise pega como um parâmetro uma função, e nessa função, nós automaticaticamente ganhamos acesso a 2 parâmetros: resolve e reject. O parâmetro resolve é utilizado para mostrar que o que nós esperávamos aconteceu, e o parâmetro reject é utilizado para mostrar que algo deu errado.

A estrutura básica de uma Promise é:

new Promise((resolve, reject) => {
    if(tudo deu certo)
        resolve();

    if(ocorreu um erro){
        reject();
    }
});

Consumindo Promises

Para consumir nossa Promise, vou fazer o seguinte:

let vaiAprenderPromises = ... //aqui vai o código visto

//chamar nossa promise

let lerConteudo = () => {
    vaiAprenderPromises
        .then(realizada => { console.log(realizada) })
        .catch(rejeitada => { console.log(rejeitada) })
}

lerConteudo();

Quando consumimdo uma promise, nós utilizamos then para pegar o resolve, e catch para pegar o reject.

Você pode juntar os dois códigos e rodar no seu browser.

Se você fizer, o output vai ser um erro:

Error: sim, eu menti

E não! Nãou sou mentirosa. Eu precisava que isso fosse a saída porque eu não sei como te entregar o biscoito. Mas eu prometo que eu vou! Então, vamos ver como.

Encadeando Promises

Como eu disse anteriormente, eu prometo que vou te entregar o biscoito.


let entregarBiscoito = () => {
    return new Promise((resolve, reject) => {
        resolve("O biscoito está indo!");
    })
}

Note que agora nos estamos apenas resolvendo a promise. Nesses casos, o código pode ser reescrito como abaixo:


let entregarBiscoito = () => {
    return Promise.resolve("O biscoito está indo!");
}

A promessa de entregarBiscoito só pode começar depois de vaiAprenderPromises.


let mentirosa = false;

let vaiAprenderPromises = ... //aqui vai o código visto antes

let entregarBiscoito = ... //aqui vai o código visto antes

let lerConteudo = () => {
    vaiAprenderPromises
        .then(entregarBiscoito)
        .then(realizada => { console.log(realizada) })
        .catch(rejeitada => { console.log(rejeitada) })
}

lerConteudo();

Agora, você pode rodar esse código e preenchê-lo com os code snippets vistos anteriormente.

O output vai ser:

O biscoito está indo!

E aqui está: :cookie:

Async e await

Considere o código a seguir:

fetch('https://jsonplaceholder.typicode.com/todos')
  .then(response => response.json())
  .then(json => console.log(json))
  .catch(err => console.log(err))

Aqui, estamos usando encadeamento de Promises. Mas imagine um cenário onde dentro de then você tenha que esperar por outra promise, o que vai gerar outro then e assim vai. Seriam vários encadeamentos.

Para evitar isso, podemos usar as keywords async e await dentro de uma função para encadear promises de um jeito melhor.


const getTodos = async () => {
    let response = await fetch('https://jsonplaceholder.typicode.com/todos');
    let data = await response.json();
    return data;
}

getTodos().then(data => console.log(data));

Primeiro, colocamos todo o código que queremos dentro de uma função, que vai ser async. Nesse caso, a função vai ser getTodos. Lembre-se que essa função retorna uma promise, então quando getTodos é chamada, nós ainda vamos precisar do método then.

Dentro de uma função async, nós podemos tratar nossas Promises como um código não bloqueável escrevendo a keyword await. Não é mais necessário encadear promises e o código fica muito mais legível.

Como aprender mais

Materiais úteis

  • https://www.digitalocean.com/community/tutorials/javascript-promises-for-dummies#understanding-promises
  • https://www.luiztools.com.br/post/programacao-assincrona-em-nodejs-callbacks-e-promises/
  • https://javascript.info/async-await
  • https://bigcodenerd.org/resolving-promises-sequentially-javascript/
  • https://www.youtube.com/watch?v=CWjNefiE47Y&list=PL4cUxeGkcC9jx2TTZk3IGWKSbtugYdrlu&index=10
  • https://www.youtube.com/watch?v=vn3tm0quoqE
← SequelizeTypescript →
  • O que é?
    • Exemplo de código síncrono
    • Exemplo de código assíncrono
  • Callback
    • Callback Hell
  • Promises
    • Consumindo Promises
    • Encadeando Promises
  • Async e await
  • Como aprender mais
    • Materiais úteis
App Masters
App masters
Content
More
BlogGitHub
Copyright © 2022 App Masters