kb.erickguedes.com
Node.js: Backend JavaScript em Produção

Event Loop, Módulos e Gerenciamento de Pacotes

Aula 1 de 7

Node.js Runtime

Node.js é um runtime JavaScript baseado no motor V8 do Chrome. Ele permite executar JavaScript no servidor com acesso ao sistema de arquivos, rede e processos.

const os = require('os');
console.log('Platform:', os.platform());
console.log('CPUs:', os.cpus().length);
console.log('Memory:', os.totalmem() / 1024 / 1024 / 1024, 'GB');

Event Loop

O event loop é o coração do Node.js. Ele gerencia operações assíncronas em um modelo single-thread non-blocking.

// Fases do event loop: timers -> pending -> idle/prepare -> poll -> check -> close
console.log('1 - Síncrono');

setTimeout(() => console.log('2 - Timers (setTimeout)'), 0);
setImmediate(() => console.log('3 - Check (setImmediate)'));

process.nextTick(() => console.log('4 - nextTick (antes da próxima fase)'));

Promise.resolve().then(() => console.log('5 - Microtask (Promise.then)'));

console.log('6 - Síncrono');

// Ordem: 1, 6, 4, 5, 2, 3

Microtasks vs Macrotasks

  • Microtasks: process.nextTick, Promise.then/catch/finally
  • Macrotasks: setTimeout, setInterval, setImmediate, I/O callbacks
// nextTick tem a maior prioridade entre microtasks
process.nextTick(() => console.log('nextTick 1'));
process.nextTick(() => console.log('nextTick 2'));

Promise.resolve().then(() => console.log('Promise 1'));

// nextTick sempre executa antes de qualquer Promise

Módulos: CommonJS vs ES Modules

CommonJS (padrão no Node.js)

// math.js
const sum = (a, b) => a + b;
const sub = (a, b) => a - b;

module.exports = { sum, sub };
// ou: exports.sum = sum;
// index.js
const { sum, sub } = require('./math.js');
console.log(sum(5, 3)); // 8

ES Modules (moderno)

// package.json
{
  "type": "module"
}
// math.mjs
export const sum = (a, b) => a + b;
export const sub = (a, b) => a - b;
// index.mjs
import { sum, sub } from './math.mjs';
console.log(sum(5, 3)); // 8

Diferenças

AspectoCommonJSES Modules
CarregamentoSíncronoAssíncrono
Syntaxrequire/module.exportsimport/export
Top-level awaitNãoSim
__dirnameDisponívelimport.meta.url
// ES Modules: obter __dirname
import { fileURLToPath } from 'url';
import { dirname } from 'path';

const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);

npm e Yarn

# Inicializar projeto
npm init -y
# ou
yarn init -y

# Instalar dependências
npm install express
npm install -D typescript
npm install -g nodemon  # global

# yarn
yarn add express
yarn add -D typescript

nvm (Node Version Manager)

# Instalar versões
nvm install 18
nvm install 20

# Usar versão
nvm use 20

# Versão padrão
nvm alias default 20

package.json Scripts

{
  "name": "meu-projeto",
  "version": "1.0.0",
  "scripts": {
    "start": "node src/index.js",
    "dev": "nodemon src/index.js",
    "test": "jest",
    "lint": "eslint src/",
    "build": "tsc",
    "prestart": "npm run build"
  }
}
npm run dev
npm test
npm run lint

Lab: Exercício - Servidor com módulos e scripts

Crie um servidor HTTP modular com scripts npm:

// src/server.js
const http = require('http');
const { getTimestamp } = require('./utils.js');

const server = http.createServer((req, res) => {
  res.writeHead(200, { 'Content-Type': 'application/json' });
  res.end(JSON.stringify({
    message: 'Servidor rodando!',
    timestamp: getTimestamp()
  }));
});

const PORT = process.env.PORT || 3000;
server.listen(PORT, () => {
  console.log(`Servidor rodando na porta ${PORT}`);
});
// src/utils.js
const getTimestamp = () => new Date().toISOString();
const formatDate = (date) => date.toLocaleDateString('pt-BR');

module.exports = { getTimestamp, formatDate };
{
  "scripts": {
    "start": "node src/server.js",
    "dev": "node --watch src/server.js"
  }
}
# Testar o servidor
npm start

O event loop do Node.js prioriza process.nextTick acima de Promises, e Promises acima de timers. Módulos CommonJS são síncronos, ES Modules são assíncronos com suporte a top-level await.