Node.js - O que é, como funciona ⚡️
Tags: node, javascript, beginners, tutorial
Published: 2023-08-08 23:58:45

## O que é o Node.js?

Diferente do que muitos pensam o [Node.js](https://nodejs.org/en) não é uma linguagem de programação, e sim uma plataforma (runtime) que permite rodar código [JavaScript](https://developer.mozilla.org/pt-BR/docs/Web/JavaScript) (que no caso é uma linguagem de programação) no Servidor.

Bom, inicialmente o JavaScript foi criado para rodar apenas em Browsers, porém em 2008 foi lançada uma nova versão do Google Chrome e junto com essa nova versão veio o [V8](https://v8.dev/) que é um [interpretador de código](https://blog.geekhunter.com.br/metodos-de-traducao-compiladores-ou-interpretadores/#O_que_e_compilador) JavaScript.

E em 2009, um engenheiro de software chamado [Ryan Dahl](https://github.com/ry) executou o V8 no Servidor, ou seja, fez com que o código JavaScript fosse interpretado no lado do Servidor em vez do lado do Cliente (Browsers), e com isso nasceu o que a gente conhecem hoje como Node.js.

## Como o Node.js executa nosso código?

Vamos começar entendendo sobre Call Stack, Thread Pool, Event Loop e Callback Queue.

- Call Stack

A call stack é a pilha de processamento do nosso código, ou seja, todas as funções que executarmos irão para essa pilha (stack).

Vamos a um exemplo prático da Call Stack e vamos analisar o código abaixo:

```
function multiply(x, y) {
  return x * y;
}

function printSquare(x) {
  const square = multiply(x, x);
  console.log(square);
}

printSquare(5);
```

Ao rodarmos o código acima, o JavaScript irá ler de cima para baixo, declarar as duas funções (`multiply` e `printSquare`) e ao final de tudo, irá invocar a função `printSquare` passando o valor 5 no argumento.

Veja a imagem abaixo para melhor compreensão.

![Call Stack Steps](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lgci2vc7zj2mz4892rxo.png)

- Step 1. 

> 
Quando invocamos a função `printSquare`, é aqui que entra a nossa Call Stack em ação, como mencionei anteriormente, todas as funções que executamos no nosso código vão para a nossa call stack (pilha de processamento), então a função printSquare já está lá.

- Step 2. 

> 
Dentro da função `printSquare`, a gente chama na primeira linha a função `multiply`, então a função `multiply`, também entra na pilha de chamadas.

- Step 3. 

> 
Bem, dentro da função `multiply` não vamos mais a nenhum lugar, não chamamos nenhuma outra função ou algo do tipo, simplesmente pegamos os argumentos x e y multiplicamos um pelo outro e retornamos o resultado, então a partir do momento que a função `multiply` está retornando o resultado, o papel dela é concluído e ela sai da nossa pilha de chamadas.

> 
E agora, voltando para dentro da função `printSquare`, chamamos um `console.log()` para mostrar o resultado, então a função `console.log` entra na nossa pilha de chamadas, é executada e depois sai da pilha.

- Step 4 & 5: 

> 
E agora, como não temos mais nada para fazer dentro da função `printSquare`, o processamento do nosso código acabou e a função `printSquare` também sai da nossa call stack. 

Bom, com isso já conseguimos notar uma **característica** da Call Stack: `A primeira função que entra é a última que sai.`

A call stack tem muito peso em nosso código e por isso é muito importante sabermos sobre sua existência e entender como ela funciona.

- Single Thread

Outra característica do [Node.js](https://nodejs.org/en) é que ele é Single Thread, ou seja, só pode executar uma tarefa por vez.

“Mas como assim ele só executa uma tarefa por vez, ouço todo mundo falando que o Node.js é Non-Blocking I/O, ou seja, tem entrada e saída de dados de forma não bloqueante”.

De fato, o [Node.js](https://nodejs.org/en) não pode executar mais de uma tarefa por vez, temos apenas 1 call stack, e enquanto ela estiver ocupada, não podemos executar mais nada.

“Então, por que falam que o Node.js é Non-Blocking I/O e que pode executar mais de uma tarefa ao mesmo tempo?”

Porque de fato ele é **Non-Blocking I/O** e também de fato ele pode **executar mais de uma tarefa ao mesmo tempo**, e ele consegue fazer isto mesmo sendo Single Thread, porque por debaixo dos panos ele roda em uma biblioteca escrita em C chamada **[libuv](https://libuv.org/)**.

A libuv implementa o Thread Pool e o Event Loop, também implementa toda a parte do filesystem do Node, DNS e etc. A libuv é uma biblioteca muito completa e dá muitos poderes ao Node.

> Se quiser conhecer mais sobre a libuv, aqui estão alguns links uteis:
> [Site oficial](https://libuv.org/)
> [Github](https://github.com/libuv/libuv)
> [Libuv no Node.js](https://www.geeksforgeeks.org/libuv-in-node-js/)

Bem, vamos prosseguir, considere o seguinte código:

```
console.log('Before.');

db.query(query, function callback(error, data) {
  console.log(data);
});

console.log('After.')
```

Logo na primeira linha temos um `console.log` que já entra em nossa pilha de chamadas, é executado e sai dela.

![01 Gif](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l61eqhv2tkkhp30owwvp.gif)

Depois disso, vamos para a linha debaixo, onde temos a função db.query, e é aqui que começa a diversão.

Essa função db.query é o que chamamos de função bloqueante, o que significa que ela leva um certo tempo para ser executada, pois nesse caso ela precisa se conectar ao banco de dados, executar uma consulta, aguardar a resposta do banco de dados, e trazer as informações de volta, e tudo isso leva um certo tempo, e se o Node não tomasse nenhuma ação em cima disso, essa função db.query ficaria presa em nossa call stack, bloqueando a execução do código, ou seja, não poderíamos passar para a próxima linha até que a função db.query fosse resolvida, e é por essa razão que chamamos ela de função bloqueante, porque ela bloqueia nossa pilha de processamento.

Porém, o Node.js não deixa isso acontecer, pois ele entende que essa função db.query vai bloquear a call stack, então ele pega e joga essa função para dentro da Thread Pool e a remove da nossa call stack.


![02 Gif](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dd110phd4uk3dxg8dq70.gif)

Enquanto nossa query está sendo executada dentro da Thread Pool, nosso código continua sendo executado, então ele vai normalmente para nosso `console.log()` da última linha, executa e o remove logo em seguida, e a execução do código principal termina.

Então lá na Thread Pool, a query está sendo executada e após terminar a execução da mesma, a função de callback do db.query é lançada na “Callback Queue”.

![03 Gif](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oqo5c49jtgsux8t7dzah.gif)


Após a função de callback da db.query estar dentro da callback queue, o Event Loop entra em ação, pense nele como um while(true) que fica sempre verificando se existe alguma função pronta para ser executada dentro da callback queue.

Se o Event loop encontrar alguma função que está pronta para ser executada e nossa pilha de chamadas não tiver mais funções pendentes para serem executadas, ele puxa essa função que está pronta para ser executada para a pilha de chamadas e continua processando o código normalmente.

Lembra que dentro da função de callback da query.db tínhamos um `console.log` ? Então, em seguida, ele será executado e após sua execução será removido da pilha. E agora, como nossa função de callback não tem mais nada para executar, ela também é retirada da pilha.

E é assim que o Node.js consegue executar código assíncrono.

Bom, isso é tudo que eu pretendia escrever para esse post, talvez em um próximo post, eu escreva mais do funcionamento do Node e etc.

Espero que tenha lhe ajudado de alguma forma, seu feedback (positivo ou negativo) é sempre bem-vindo :D