DEV Community

Cover image for Promeses no JavaScript
Monts
Monts

Posted on

Promeses no JavaScript

Fluxo Assíncrono

O JavaScript é uma linguagem single-threade

Consequências

  • Deixa o usuário sem ação durante todo o tempo para a realização de uma operação;
  • Não permite que o servidor seja capaz de realizar algum outra requisição até que a atual termine,,,,,,.

Solução

  • Buscar em tornar operações muito extensas em operações assíncronas, dessa forma tornando o código mais performático e bem escrito.

Callbacks

Assim que uma operação for concluída a callback será executada

Exemplo:

const fs = require('fs');
fs.readFile('./arquivo.txt', (err, content) => {
  if (err) {
    console.error(`Erro ao ler o arquivo: ${err.message}`);
    return; 
  } 
  console.log(`Arquivo lido. Conteúdo: ${content.toString('utf8')}`);});
Enter fullscreen mode Exit fullscreen mode

No código acima é utilizado uma node-style callback (formato de callback nativa do Node.js)

O que está acontecendo:

  • No primeiro parâmetro é passado o arquivo que sera lido;
  • No segundo parâmetro é passado uma callback para tratar a resposta da função
    • Assim é possível tratar a resposta de forma diferente, dependendo de se ocorreu algum erro em meio ao processo ou se tudo ocorreu como deveria

O lado ruim das callback:

  • Nem tudo são flores, o principal problema em se usar esse método é que seu resultado estará unicamente naquela callback, o que gera a necessidade de executar uma coisa dentro da outra

Exemplo:

Callback hell

const fs = require('fs');
fs.readFile('file1.txt', (err, file1Content) => {
  if (err) return console.log(Erro ao ler arquivo 1: ${err.message});
  console.log(Lido file1.txt com ${file1Content.byteLength} bytes);
  fs.readFile('file2.txt', (err, file2Content) => {
    if (err) return console.log(Erro ao ler o arquivo 2: ${err.message});
    console.log(Lido file2.txt com ${file2Content.byteLength} bytes);
    fs.readFile('file3.txt', (err, file3Content) => {
      if (err) return console.log(Erro ao ler o arquivo 3: ${err.message});
      console.log(Lido file3.txt com ${file3Content.byteLength} bytes);
    });
  });
});
Enter fullscreen mode Exit fullscreen mode

Como mostrado no código acima, a legibilidade se torna muito mais complexa devido a necessidade de criar uma callback dentro de outra callback até concluir sua tarefa.

Possível solução:

const fs = require('fs');
const file3Callback = (err, file3Content) => {
  if (err) return console.log(Erro ao ler o arquivo 3: ${err.message});
  console.log(Lido file3.txt com ${file3Content.byteLength} bytes);
};
const file2Callback = (err, file2Content) => {
  if (err) return console.log(Erro ao ler o arquivo 2: ${err.message});
  console.log(Lido file2.txt com ${file2Content.byteLength} bytes);
  fs.readFile('file3.txt', file3Callback);
};
const file1Callback = (err, file1Content) => {
  if (err) return console.log(Erro ao ler arquivo 1: ${err.message});
  console.log(Lido file1.txt com ${file1Content.byteLength} bytes);
  fs.readFile('file2.txt', file2Callback);
};
fs.readFile('file1.txt', file1Callback);
Enter fullscreen mode Exit fullscreen mode

Como tentativa de tornar o código mais legível, são criadas varias funções com o único intuito de chamar a próxima callback, apesar de torná-lo um pouco mais legível, ainda não é performático.


Promises

A cereja do bolo para as callbacks, melhorando sua legibilidade e deixando seu código muito mais intuitivo.

  • Sua principal diferença é que ao invés de uma única callback receber tanto o sucesso quanto o erro, ela tera duas callback com funções únicas, uma lidará com o erro e a outra com o sucesso.

Ok, mas como essa mágica acontece?

Observe os dois casos a seguir:

function dividirNumerosSemPromises(num1, num2) {
  if (num2 == 0) throw new Error("Não pode ser feito uma divisão por zero");

  return num1 / num2;
}

try {
  const resultado = dividirNumeros(2, 1);
  console.log(`resultado: ${resultado}`);
} catch (e) {
  console.log(e.message);
}
Enter fullscreen mode Exit fullscreen mode

Na função síncrona dividirNumerosSemPromises o resultado da callback já é tratado dentro da função.

function dividirNumerosComPromises(num1, num2) {
  const promise = new Promise((resolve, reject) => {
    if (num2 == 0) reject(new Error("Não pode ser feito uma divisão por zero"));
    const resultado = num1 / num2;
    resolve(resultado)
  });
  return promise;
}
dividirNumeros(2, 1)
  .then(result => console.log(sucesso: ${result}))
  .catch(err => console.log(erro: ${err.message}));
Enter fullscreen mode Exit fullscreen mode

Agora na função assíncrona dividirNumerosComPromises o resultado não é tratado dentro da função, mas sim onde ela está sendo chamada. Assim, com uma mesma função é possível tratar a resposta em inúmeras formas diferentes

Then e resolve x Catch e reject

Caso não tenha percebido, no segundo caso essas duas palavrinhas são utilizadas, mas o que elas significam?

  • Then: forma de tratar o sucesso de uma callback, pode ser utilizado varias vezes no mesmo contexto;
  • Catch: igualmente ao then, porém sua tarefa é tratar o erro.

Estrutura da Promese:

const p = new Promise((resolve, reject) => {
  // Aqui é onde vamos realizar a lógica que precisamos
  // para "tentar cumprir" a promessa
});
Enter fullscreen mode Exit fullscreen mode

Ao escrevê-la, não se esqueça de utilizar a palavra-chave new e da arrow function como parâmetro da Promese.

const fs = require('fs');
function readFilePromise (fileName) {
  return new Promise((resolve, reject) => {

    fs.readFile(fileName, (err, content) => {
      if (err) return reject(err);
      resolve(content);
    });

  });
}
Enter fullscreen mode Exit fullscreen mode

Perceba, no exemplo acima estamos utilizando do modulo interno fs apenas com o intuito de ilustrar, o importante aqui é perceber como o resolve e o reject são utilizados.

readFilePromise('./file.txt') // A função me promete que vai ler o arquivo
  .then((content) => { // Caso ela cumpra o que prometeu
    console.log(Lido arquivo com ${content.byteLength} bytes); // Escrevo o resultado no console
  })
  .catch((err) => { // Caso ela não cumpra o que prometeu
    console.error(Erro ao ler arquivo: ${err.message}); // Escrevo o erro no console
  });
Enter fullscreen mode Exit fullscreen mode

Sei que é muita coisa, mas aos pouquinhos você vai pegar o jeito :)

Discussion (0)