Node.js: Introdução ao Node.js
Alice é uma desenvolvedora de back-end. Sua empresa precisava criar um back-end com API REST para um aplicativo móvel em duas semanas. A equipe era composta inteiramente por desenvolvedores de front-end que só sabiam JavaScript, e ninguém estava disposto a dedicar tempo para aprender uma nova linguagem. O gerente de projeto chegou a considerar a contratação de um desenvolvedor de Python, mas simplesmente não havia tempo suficiente. Justamente quando a equipe começava a ficar ansiosa, Alice descobriu o Node.js — um ambiente de execução que roda JavaScript no servidor. Os desenvolvedores front-end puderam escrever APIs de back-end usando a sintaxe com a qual já estavam familiarizados, e o projeto foi lançado com sucesso duas semanas depois. Isso fez Alice perceber que o Node.js não é apenas uma ferramenta — é uma ponte que conecta o front-end e o back-end.
Você aprenderá:
- Definição e objetivo principal do Node.js
- A arquitetura subjacente do motor V8 e do Node.js
- Como funcionam a E/S orientada a eventos e a E/S sem bloqueio
- Principais diferenças entre o Node.js e o JavaScript do navegador
- Políticas de controle de versão do Node.js e casos de uso típicos
1. O que é o Node.js?
(1) Definição
O Node.js é um ambiente de execução de JavaScript baseado no motor V8 do Chrome. Ele permite que o JavaScript seja executado diretamente no servidor, independentemente do navegador. O Node.js não é uma nova linguagem nem uma estrutura, mas sim uma plataforma de execução do JavaScript no lado do servidor.
(2) Contexto de sua origem
Em 2009, Ryan Dahl criou o Node.js com base no motor V8. Seu objetivo inicial era resolver o problema de bloqueio causado pelas operações de E/S do lado do servidor — os servidores web tradicionais bloqueiam threads ao lidar com operações de E/S, como leituras de arquivos e solicitações de rede, enquanto o Node.js utiliza uma abordagem orientada a eventos, permitindo que uma única thread lide de forma eficiente com um grande número de conexões simultâneas.
▶ Exemplo: Seu primeiro script em Node.js
Criar arquivo hello.js:
console.log('Hello, Node.js!');
console.log('Node.js version:', process.version);
console.log('Platform:', process.platform);
Execute o seguinte no terminal:
node hello.js
Resultado esperado:
Hello, Node.js!
Node.js version: v20.11.0
Platform: win32
2. O motor V8 e a arquitetura do Node.js
(1) O papel do motor V8
O V8 é um mecanismo de JavaScript desenvolvido pelo Google que compila código JavaScript em código de máquina para execução. O Node.js possui o mecanismo V8 integrado, e é por isso que oferece um desempenho tão alto. A tecnologia de compilação just-in-time (JIT) do V8 permite que o JavaScript seja executado a velocidades próximas às do código nativo.
(2) Camadas da arquitetura do Node.js
A arquitetura do Node.js é dividida em quatro camadas, de baixo para cima:
| Nível | Composição | Função |
|---|---|---|
| Camada de código JavaScript | Arquivos .js criados pelo usuário | Lógica de negócios |
| Camada de API do Node.js | Módulos como fs, http e path | Oferece recursos do lado do servidor |
| Camada de ligações do Node.js | Código da ponte em C++ | Conectando o JavaScript à biblioteca C subjacente |
| Bibliotecas de baixo nível | V8, libuv, OpenSSL, etc. | Mecanismos e chamadas de sistema |
(3) O papel fundamental da libuv
A libuv é a biblioteca de E/S assíncrona do Node.js, que fornece um ciclo de eventos, um conjunto de threads e uma abstração multiplataforma para E/S assíncrona. Ela permite que o Node.js lide com operações assíncronas — como E/S de arquivos, operações de rede e temporizadores — de maneira consistente em diferentes sistemas operacionais.
▶ Exemplo: Visualizando informações sobre dependências do Node.js
console.log('V8 version:', process.versions.v8);
console.log('libuv version:', process.versions.libuv);
console.log('OpenSSL version:', process.versions.openssl);
console.log('Node.js version:', process.version);
Resultado:
V8 version: 11.3.244.8
libuv version: 1.46.0
OpenSSL version: 3.0.12
Node.js version: v20.11.0
▶ Exemplo:(4) Diagrama de arquitetura
graph TB
A["JavaScript Code<br/>(User-written .js Documents)"] --> B["Node.js API<br/>(fs / http / path / ...)"]
B --> C["Node.js Bindings<br/>(C++ Bridge Layer)"]
C --> D1["V8 Engine<br/>(JavaScript Compile and Run)"]
C --> D2["libuv<br/>(Event Loop + Asynchronous I/O)"]
C --> D3["Other C Libs<br/>(OpenSSL / zlib / c-ares)"]
D2 --> E["Operating System<br/>(Documents / Internet / Process)"]
3. E/S orientada a eventos e não bloqueante
(1) Modelo orientado a eventos
O Node.js utiliza uma arquitetura orientada a eventos: o programa responde a diversas operações registrando callbacks de eventos, em vez de realizar sondagens ativas. Quando uma operação de E/S é concluída, o loop de eventos coloca o callback correspondente em uma fila para aguardar a execução.
(2) O significado da E/S sem bloqueio
Os servidores tradicionais bloqueiam a thread atual durante a leitura de um arquivo até que ele tenha sido lido por completo. O Node.js retorna imediatamente após iniciar uma solicitação de E/S, continua executando o código subsequente e, em seguida, processa o resultado por meio de um callback assim que a operação de E/S é concluída. Essa abordagem permite que uma única thread lide com centenas de solicitações simultâneas ao mesmo tempo.
(3) Introdução ao ciclo de eventos
O loop de eventos é o principal mecanismo de agendamento do Node.js, que é executado em um ciclo passando pelas seguintes fases:
- horas: Executar a função de retorno de chamada do setTimeout / setInterval
- Callbacks pendentes: Callbacks que realizam operações do sistema
- inativo, preparar: Para uso interno
- poll: Recupera novos eventos de E/S e executa callbacks de E/S
- verificar: Executar a função de retorno setImmediate
- callbacks de fechamento: Executar os callbacks do evento de fechamento
▶ Exemplo: Leitura de arquivos em modo bloqueante versus não bloqueante
Modo de bloqueio (não recomendado):
const fs = require('fs');
const data = fs.readFileSync('/etc/hosts', 'utf8');
console.log('File read (blocking):', data.length, 'bytes');
console.log('This line runs after file is read');
Modo sem bloqueio (recomendado):
const fs = require('fs');
fs.readFile('/etc/hosts', 'utf8', (err, data) => {
if (err) throw err;
console.log('File read (non-blocking):', data.length, 'bytes');
});
console.log('This line runs immediately');
Saída (modo sem bloqueio):
This line runs immediately
File read (non-blocking): 250 bytes
Observe que, no modo não bloqueante, a mensagem “Esta linha é executada imediatamente” é exibida primeiro, indicando que readFile não bloqueou o código subsequente.
4. Node.js x JavaScript do navegador
(1) Principais diferenças
O Node.js e o JavaScript no navegador utilizam a mesma especificação de linguagem (ECMAScript), mas seus ambientes de execução e as APIs disponíveis são completamente diferentes.
| Critérios de comparação | Node.js | JavaScript do navegador |
|---|---|---|
| Ambiente de execução | Servidor | Navegador |
| Sistema de módulos | CommonJS / ESM | ESM |
| Objeto global | global / processo | janela / documento |
| Sistema de arquivos | Acesso direto por meio do módulo fs | Não pode ser acessado diretamente |
| E/S de rede | Módulos http / net | fetch / XMLHttpRequest |
| Manipulação do DOM | Sem DOM | API do DOM |
| Gerenciador de pacotes | npm | Nenhum (ou via CDN) |
| Principais usos | Aplicativos de servidor, ferramentas de CLI | Interações na Web, renderização da interface do usuário |
(2) Semelhanças
- Todos estão em conformidade com o padrão ECMAScript
- Ambos utilizam o motor V8 (Chrome e Node.js)
- Ambos oferecem suporte a Promise e async-await
- Todos eles possuem um mecanismo de ciclo de eventos
▶ Exemplo: mesma sintaxe, APIs diferentes
Código do navegador:
document.getElementById('output').textContent = 'Hello from browser';
Código Node.js:
const fs = require('fs');
fs.writeFileSync('output.txt', 'Hello from Node.js');
A sintaxe do JavaScript é a mesma, mas os objetos manipulados são completamente diferentes: os navegadores manipulam o DOM, enquanto o Node.js manipula o sistema de arquivos.
5. Casos de uso típicos do Node.js
(1) Serviço de API REST
O Node.js é ideal para a criação de APIs RESTful. Seu modelo de E/S não bloqueante lida com eficiência com muitas solicitações simultâneas, e o JSON é o formato de dados nativo do JavaScript, o que elimina a sobrecarga da serialização.
(2) Ferramentas de CLI
Webpack, Babel, ESLint e npm são todas ferramentas de linha de comando (CLI) desenvolvidas com o Node.js. O Node.js oferece um amplo conjunto de APIs para lidar com o sistema de arquivos, processos filhos e argumentos de linha de comando.
(3) Aplicações em tempo real
Cenários como sistemas de bate-papo, colaboração on-line e notificações em tempo real exigem conexões persistentes e bidirecionais. O suporte a WebSocket e a arquitetura orientada a eventos do Node.js são naturalmente adequados a essas necessidades.
(4) Microsserviços
O Node.js inicia rapidamente e consome pouca memória, o que o torna ideal para microsserviços leves. Cada microsserviço pode ser implantado e dimensionado de forma independente.
(5) Rastreamento da Web e coleta de dados
Quando combinado com bibliotecas como a Cheerio, o Node.js consegue rastrear e analisar dados da web com eficiência, e a E/S assíncrona torna as solicitações simultâneas extremamente eficientes.
▶ Exemplo: Comparação de casos de uso
| Cenário | Vantagens | Projetos representativos |
|---|---|---|
| API REST | E/S não bloqueante + JSON nativo | Express / Fastify / Koa |
| Ferramentas de linha de comando | Operações com arquivos + subprocessos | Webpack / Babel / ESLint |
| Aplicativos em tempo real | WebSocket + Orientados a eventos | Socket.IO / ws |
| Microsserviços | Leve + Rápido de configurar | NestJS / Seneca |
| Web Scraping | Concorrência assíncrona + Análise do DOM | Puppeteer / Cheerio |
▶ Exemplo: Criar um servidor HTTP em 5 linhas de código
const http = require('http');
const server = http.createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ message: 'Hello from Node.js API' }));
});
server.listen(3000, () => console.log('Server running on port 3000'));
node server.js
Server running on port 3000
Acesse http://localhost:3000 para visualizar a resposta em JSON.
6. Política de versões do Node.js
(1) LTS e versão atual
O Node.js utiliza uma estratégia de lançamento em duas vertentes:
| Comparação | LTS (Suporte de Longo Prazo) | Atual |
|---|---|---|
| Ciclo de lançamento | Um lançamento principal a cada dois anos | Um lançamento principal a cada 6 meses |
| Período de manutenção | 30 meses | Aproximadamente 6 meses |
| Estabilidade | Alta; inclui apenas correções de bugs e patches de segurança | Baixa; inclui os recursos mais recentes |
| Casos de uso | Ambiente de produção | Experimentar novos recursos, testes |
| Regras de numeração de versões | Números pares (18, 20, 22...) | Números ímpares (19, 21, 23...) |
(2) Recomendações para a escolha de uma versão
- Projetos de produção: Utilize sempre a versão LTS ativa
- Fase de Aprendizagem: Recomendamos o uso do Active LTS, pois ele oferece os recursos e o ecossistema mais abrangentes.
- Recurso experimental: A versão atual pode ser usada, mas não é recomendada para uso em produção.
(3) Ferramentas de controle de versão
Recomendamos o uso do nvm (Node Version Manager) para gerenciar e alternar entre as versões do Node.js.
▶ Exemplo: Gerenciamento de versões com o nvm
nvm install 20
nvm use 20
nvm ls
v18.17.0
-> v20.11.0
system
default -> 20 (-> v20.11.0)
▶ Exemplo: Verificar a versão atual do Node.js e seu status
node -v
node -e "console.log(process.release.lts ? 'LTS: ' + process.release.lts : 'Current (non-LTS)')"
v20.11.0
LTS: Iron
❓ Perguntas Frequentes
P: O Node.js é uma nova linguagem? R: Não. O Node.js é um ambiente de execução para JavaScript que permite que o JavaScript seja executado no lado do servidor; a linguagem em si continua sendo o JavaScript.
P: Por que o Node.js é adequado para aplicativos com uso intensivo de E/S? R: O Node.js utiliza um modelo de E/S orientado a eventos e não bloqueante, permitindo que uma única thread lide com um grande número de solicitações de E/S simultâneas ao mesmo tempo, sem bloquear todo o processo devido a uma única operação lenta.
P: Para que o Node.js não é adequado? R: Tarefas que exigem muito da CPU, como codificação de vídeo, cálculos matemáticos extensos e processamento de imagens. O uso prolongado da CPU bloqueia o ciclo de eventos, fazendo com que todas as solicitações fiquem em fila. Esses tipos de tarefas devem ser tratados por threads de trabalho ou serviços externos.
P: Preciso aprender JavaScript antes de aprender Node.js? R: Sim. O Node.js não é uma nova linguagem em si; ele executa JavaScript. É preciso dominar os conceitos básicos da sintaxe do JavaScript, funções, objetos e programação assíncrona (Promises / async-await) antes de poder usar o Node.js de forma eficaz.
P: Qual é a diferença entre o Node.js e o Deno? R: O Deno também é um ambiente de execução de JavaScript/TypeScript, criado por Ryan Dahl, o criador original do Node.js. Principais diferenças: o Deno oferece suporte nativo ao TypeScript, usa ES Modules em vez de CommonJS, possui uma sandbox de segurança (que desativa o acesso a arquivos e à rede por padrão), não requer um diretório
package.jsonounode_modulese inclui ferramentas integradas de formatação e teste em sua biblioteca padrão. O ecossistema do Deno ainda está em crescimento, enquanto o do Node.js é mais maduro.
P: O Node.js é monotread? R: O código JavaScript é executado em um único thread, mas o Node.js utiliza o pool de threads da libuv (4 threads por padrão) nos bastidores para lidar com E/S de arquivos, consultas de DNS e outras operações. Ele também oferece suporte a threads de trabalho para lidar com tarefas que exigem muito da CPU.
P: O que preciso instalar para aprender Node.js? R: Basta instalar o Node.js (que vem com o gerenciador de pacotes npm) e um editor de código (recomendamos o VS Code). Após a instalação, execute
node -vno terminal para verificar se está funcionando.
📖 Resumo
- O Node.js é um ambiente de execução de JavaScript do lado do servidor baseado no mecanismo V8; não se trata de uma nova linguagem.
- A arquitetura é composta por quatro camadas: código JavaScript → API do Node.js → ligações → bibliotecas subjacentes (V8 / libuv)
- A E/S orientada a eventos e não bloqueante é o mecanismo central para a alta concorrência do Node.js
- O Node.js usa a mesma sintaxe do JavaScript do navegador, mas suas APIs e ambientes de execução são completamente diferentes.
- Casos de uso típicos: APIs REST, ferramentas de linha de comando, aplicativos em tempo real, microsserviços, rastreadores da web
- Certifique-se de usar a versão LTS em ambientes de produção e gerencie várias versões com o nvm.
📝 Exercícios
- Instale o Node.js (recomenda-se a versão LTS), execute
node -vpara verificar se a instalação foi bem-sucedida e anote o número da versão e se trata de uma versão LTS. - Crie um arquivo chamado
hello.js, useconsole.logpara exibir seu nome e o número da versão do Node.js, execute-o e faça uma captura de tela - Escreva um script que utilize o objeto
processpara exibir as seguintes informações: versão do Node.js, plataforma do sistema operacional, diretório de trabalho atual e arquitetura da CPU. - Use
fs.readFilepara ler um arquivo de texto no modo não bloqueante e exibir seu conteúdo; em seguida, observe a ordem de execução das funções de retorno de chamada - Compare
fs.readFileSync(bloqueante) efs.readFile(não bloqueante) exibindo os carimbos de data e hora antes e depois da chamada de retorno, respectivamente, durante a leitura do mesmo arquivo, para ilustrar a diferença na execução de cada um.
7. Exemplo completo: script para ler informações do sistema
O script a seguir utiliza os módulos integrados do Node.js para ler e exibir informações do sistema, demonstrando os recursos básicos do Node.js como um ambiente de execução do lado do servidor:
const os = require('os');
const fs = require('fs');
const path = require('path');
const sysInfo = {
nodeVersion: process.version,
platform: process.platform,
arch: process.arch,
hostname: os.hostname(),
totalMemoryMB: Math.round(os.totalmem() / 1024 / 1024),
freeMemoryMB: Math.round(os.freemem() / 1024 / 1024),
cpuCores: os.cpus().length,
cpuModel: os.cpus()[0].model,
uptimeHours: (os.uptime() / 3600).toFixed(2),
cwd: process.cwd(),
homedir: os.homedir()
};
const output = JSON.stringify(sysInfo, null, 2);
console.log(output);
const filePath = path.join(os.homedir(), 'nodejs-sysinfo.txt');
fs.writeFile(filePath, output, 'utf8', (err) => {
if (err) {
console.error('Write failed:', err.message);
return;
}
console.log('System info saved to:', filePath);
});
Resultado esperado:
{
"nodeVersion": "v20.11.0",
"platform": "win32",
"arch": "x64",
"hostname": "DESKTOP-ABC123",
"totalMemoryMB": 16384,
"freeMemoryMB": 8192,
"cpuCores": 8,
"cpuModel": "Intel(R) Core(TM) i7-12700K",
"uptimeHours": "48.32",
"cwd": "C:\\projects\\node-demo",
"homedir": "C:\\Users\\Alice"
}
System info saved to: C:\Users\Alice\nodejs-sysinfo.txt
O script demonstra três recursos principais do Node.js: recuperação de informações do sistema operacional (os), gravação em um arquivo (fs) e tratamento de caminhos (path). Ele também utiliza E/S não bloqueante para gravar em um arquivo — a função de retorno de chamada para fs.writeFile é executada após console.log, ilustrando a natureza orientada a eventos do Node.js.