Introdução ao Fluxo Assíncrono - Node.js
Tags: beginners, javascript, node, braziliandevs
Published: 2022-03-14 21:21:53

## Tabela de Conteúdos

- [Callback](#callback)
- [Promises](#promises)
- [Async/Await](#asyncawait)
- [Links Úteis](#links-úteis)

---

## Callback

### O que é?

É uma função que será executada por outra função, normalmente utilizada para controle de fluxo assíncrono.

### O que faz?

Como dito em sua definição, é uma função que será chamada por outra função, dessa forma conseguimos preservar o fluxo do JS, permitindo que a própria linguagem faça o controle de chamadas, impedindo _“travamentos”_ em operações de alta complexidade.

### Sintaxe

Uma Callback é uma função que deve ser passada como argumento para outra função, dessa forma a função que irá receber a outra por parâmetro fica responsável pela execução da Callback. Essa função pode ser uma função convencional, uma Arrow function ou até uma função anônima.

``` javascript
function myCallback(err, content) {};

fs.readFile('./myFile.txt', myCallback);
```
``` javascript
const myCallback = (err, content) => {};

fs.readFile('./myFile.txt', myCallback);
```
``` javascript
fs.readFile('./myFile.txt', (err, content) => {});
```

A função de Callback também pode seguir um padrão de estruturação, no caso de callbacks para métodos nativos do Node, tem-se o padrão de parâmetros.

Onde temos dois parâmetros, no qual o primeiro refere-se a algum erro que possa ocorrer durante a execução e o segundo é o valor que esperamos conseguir.

<br />

<small>[Voltar ao topo](#tabela-de-conteúdos)</small>

___

## Promises

### O que é?

É uma API nativa do JS desde o ES6, disponibilizando formas de se lidar com o sucesso e fracasso de operações assíncronas.

### O que faz?

As Promises surgiram para resolver o problema de aninhamento de Callbacks _(callback hell)_, deixando a leitura, e por consequência a manutenção, de códigos assíncronos mais fácil.

As Promises resolvem esse problema através da disponibilização de métodos para o tratamento de sucessos ou erros, esses métodos por sua vez irão executar uma Callback definida por nós.

__A vantagem das Promises__ em relação aos aninhamentos de Callbacks __é que não precisamos aninhar Promises, apenas concatená-las__, dessa forma é muito mais fácil de entender o fluxo.

### Sintaxe

#### Criação

Definimos uma Promise a partir de sua instância, `new Promise()`, e passamos por parâmetros uma Callback que deverá receber dois argumentos, o primeiro é a função que será chamada em caso de sucesso _(resolve)_ e o segundo é a função que será chamada em caso de fracasso _(reject)_.

Normalmente criamos a Promise dentro de outra função que irá _"envelopar”_ ela e por conveniência a Callback passada a Promise costuma ser uma função anônima.

``` javascript
function myPromiseFunction() {
  const promise = new Promise((resolve, reject) => {
    if (/*condition to fail*/) reject(new Error(/*mensagem de erro*/);

    resolve();
  });

  return promise;
}
```
``` javascript
function divide(num, divisor) {
  const promise = new Promise((resolve, reject) => {
    if (divisor === 0) {
      reject(new Error('Não é possível dividir por zero!'))
    }

    resolve(num / divisor);
  });

  return promise;
}
```

#### Utilização

Para consumirmos uma Promise devemos utilizar os métodos `.then()` e `.catch()`, eles executam as funções de sucesso e falha, respectivamente. Dessa forma, se necessário, podemos concatenar diversos métodos `.then()`, substituindo assim o aninhamento de Callbacks.

Esses métodos esperam receber uma Callback que será executada assim que a Promise for resolvida, gerando um sucesso ou uma falha.

``` javascript
myPromiseFunction()
  .then(() => {})  // sucesso
  .then(() => {})  // sucesso
  .catch(() => {});  // falha (caso falhar)
```
``` javascript
divide(4, 2)
  .then((resultado) => { console.log(resultado) })  // 2
  .catch(() => {});  // falha (caso falhar)
```
``` javascript
divide(4, 0)
  .then((resultado) => { console.log(resultado) })  // sucesso
  .catch((err) => { console.log(err) });  // Não é possível dividir por zero!
```

<br />

<small>[Voltar ao topo](#tabela-de-conteúdos)</small>

___

## Async/Await

### O que é?
São palavras-chaves do JS que nos permitem trabalhar com código assíncrono com uma sintaxe similar a do código síncrono.

### O que faz?
Nem sempre precisamos utilizar a API das Promises, algumas vezes simplesmente queremos somente resgatar um valor, ou realizar operações simples, nesses casos entra o `async/await`.

Utilizando o `async/await` na função seu retorno será uma Promise, porém não será necessária a utilização dos métodos `.then()` e `.catch()`, pois tanto o tratamento de erros, quanto a execução de ações são feitos dentro da própria função.

### Sintaxe
A sintaxe para a utilização de `async/await` é extremamente simples e similar a sintaxe de uma função síncrona comum, a única diferença é a utilização da palavra reservada __async__, antes da definição da função e o uso do __await__ nas funções/métodos que retornam Promises.

E o tratamento de erros em funções de `async/await` é feito através do bloco `try/catch`.

``` javascript
async myAsyncFunction() {
  try {
    await somePromise();
  } catch (err) {
    /*tratamento do erro*/;
  }
};
```
``` javascript
async function divide(num, divisor) {
  try {
    if (divisor === 0) {
      new Error('Não é possível dividir por zero!');
    }

    return num / divisor;
  } catch (err) {
    console.log(err);
  }
}
```

** _Vale a observação. Podemos criar funções assíncronas mais complexas com `async/await`, assim como faríamos utilizando `new Promise()`, porém a API de Promise consegue fazer essa função melhor, pois permite definir de maneira mais simples e legível as Callbacks caso a caso._

<br />

<small>[Voltar ao topo](#tabela-de-conteúdos)</small>

---

## Links Úteis

- [MDN - Promises](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)
- [W3Schools - Promises](https://www.w3schools.com/js/js_promise.asp)

<br />

<small>[Voltar ao topo](#tabela-de-conteúdos)</small>