Node.js: fundamentos, arquitetura assíncrona e aplicações para concursos

Entenda como o Node.js executa JavaScript fora do navegador e revise V8, Libuv, event loop, NPM e programação assíncrona para a prova.

Por
Publicado em
10 min. de leitura

Fala aí, Padawan! Node.js é um dos assuntos que mais aparecem quando a banca quer misturar JavaScript, desenvolvimento web, programação assíncrona, APIs e arquitetura orientada a eventos. Entender essa tecnologia é importante porque as questões costumam explorar tanto conceitos básicos — como “Node.js não é uma linguagem” — quanto detalhes de funcionamento, como V8, Libuv, event loop, NPM, módulos, Express, callbacks, Promises, async/await e EventEmitter.

Antes de tudo, guarde uma ideia central: Node.js é um ambiente de execução que permite rodar JavaScript fora do navegador. Em vez de limitar a linguagem à criação de páginas interativas no lado do cliente, ele possibilita usar JavaScript em servidores, APIs, ferramentas de linha de comando, automações, manipulação de arquivos, comunicação em rede e acesso a bancos de dados.

Node.js não é uma linguagem de programação

JavaScript é a linguagem; Node.js é o ambiente responsável por executar essa linguagem fora do navegador. Quando uma questão disser que Node.js é uma nova linguagem, um framework exclusivamente front-end ou um navegador, a afirmação estará errada.

O JavaScript continua sendo uma linguagem de alto nível, dinamicamente tipada, fracamente tipada e multiparadigma. “Dinamicamente tipada” significa que o tipo de uma variável é determinado em tempo de execução. “Fracamente tipada” significa que a linguagem pode realizar algumas conversões automáticas entre tipos. Já “multiparadigma” indica que ela permite diferentes estilos de programação, como programação imperativa, funcional e orientada a objetos.

O motor V8

O Node.js utiliza o motor V8, criado originalmente para o Google Chrome. O V8 interpreta, compila e executa o código JavaScript. Em motores modernos, esse processo não se limita a interpretar cada instrução lentamente: o V8 aplica compilação JIT, sigla de Just in Time, transformando partes do código em instruções de máquina durante a execução.

Sua função principal é transformar e executar o código JavaScript com desempenho elevado.

Arquitetura orientada a eventos e não bloqueante

Node.js foi projetado para trabalhar muito bem com operações de entrada e saída, chamadas de I/O. Exemplos de I/O são leitura de arquivos, consultas a bancos de dados, conexões de rede e requisições HTTP. Essas tarefas costumam envolver espera. Em vez de deixar a aplicação parada, o Node.js inicia a operação e continua executando outras atividades.

Esse comportamento é chamado de non-blocking, ou não bloqueante. A ideia não é que tudo aconteça magicamente ao mesmo tempo, mas que a thread principal de JavaScript não fique parada aguardando cada operação demorada. Quando uma tarefa termina, seu resultado volta para uma fila e será tratado no momento adequado.

Event loop, Libuv e thread principal

O event loop, ou laço de eventos, coordena a execução de callbacks e tarefas assíncronas. Ele verifica filas de eventos e encaminha funções para execução quando a pilha de chamadas está livre. Em termos simples, é como um organizador que decide quando cada resposta pendente poderá ser processada.

A Libuv é a biblioteca escrita em C que oferece ao Node.js recursos multiplataforma para I/O assíncrono, timers, rede, DNS e um conjunto interno de threads, chamado worker pool. Enquanto o V8 executa JavaScript, a Libuv ajuda o ambiente a conversar com o sistema operacional.

É comum dizer que Node.js é single-thread. Em provas, isso normalmente significa que o código JavaScript da aplicação é executado, por padrão, em uma thread principal. Entretanto, o ambiente pode delegar tarefas para o sistema operacional, para o worker pool da Libuv ou para recursos como worker threads. Portanto, “single-thread” não significa que absolutamente todo o processo utiliza apenas uma única thread.

Primeiro programa

Depois de instalar o Node.js, um arquivo JavaScript pode ser executado diretamente pelo terminal. Suponha que o arquivo se chame app.js.

Primeiro programa em Node.js

console.log(“Hello, World!”);

1. A função console.log envia uma mensagem para a saída padrão.

2. Salve o código em app.js.

3. No terminal, execute node app.js.

4. O terminal exibirá Hello, World!.

Módulos e require

Node.js possui módulos internos para tarefas comuns. O módulo os fornece informações sobre o sistema operacional; fs trabalha com arquivos; http permite criar servidores HTTP; events oferece a classe EventEmitter. No padrão CommonJS, um módulo pode ser carregado com require().

A instrução const http = require(‘http’) carrega o módulo HTTP e armazena sua interface na constante http. É importante diferenciar require(), que importa o módulo, de createServer(), que cria efetivamente um servidor.

NPM e package.json

NPM significa Node Package Manager. Ele é o gerenciador de pacotes normalmente instalado junto com o Node.js. Seu papel é instalar, remover, atualizar e listar bibliotecas, além de executar scripts definidos no projeto. NPM não gerencia memória e não é o motor de execução JavaScript.

O comando npm init cria o arquivo package.json, que registra informações do projeto, dependências e scripts. A forma npm init -y cria o arquivo aceitando automaticamente os valores padrão. Para instalar o Express, por exemplo, usamos npm install express. Para listar pacotes instalados, usamos npm list ou npm ls.

Servidor HTTP com Node.js

O módulo http permite criar um servidor. O servidor recebe um objeto de requisição e um objeto de resposta. O parâmetro req representa a requisição recebida e normalmente é uma instância de http.IncomingMessage; res é usado para montar e enviar a resposta.

Servidor HTTP básico

const http = require(‘http’);

const server = http.createServer((req, res) => {
  res.writeHead(200, { ‘Content-Type’: ‘text/plain; charset=utf-8’ });
  res.end(‘Servidor funcionando!’);
});

server.listen(8080, () => {
  console.log(‘Servidor disponível em http://localhost:8080’);
});

1. A primeira linha importa o módulo http.

2. createServer cria o servidor e recebe uma função executada a cada requisição.

3. req representa a requisição recebida; res representa a resposta.

4. writeHead define o status 200 e o tipo de conteúdo.

5. res.end finaliza a resposta e envia o texto ao cliente.

6. listen faz o servidor aguardar conexões na porta 8080.

Express e APIs REST

Express é um framework para desenvolvimento de aplicações web e APIs. Ele simplifica a criação de rotas, o tratamento de requisições e o envio de respostas. Uma rota associa um método HTTP e um endereço a uma função.

Em uma API REST, GET costuma consultar dados; POST cria recursos; PUT substitui um recurso inteiro; PATCH atualiza parcialmente; DELETE remove. Uma rota como /usuarios/:id usa um parâmetro de rota para identificar um usuário específico.

API simples com Express

const express = require(‘express’);
const app = express();

app.use(express.json());

app.get(‘/usuarios’, (req, res) => {
  res.json([{ id: 1, nome: ‘Leia’ }]);
});

app.post(‘/usuarios’, (req, res) => {
  res.status(201).json(req.body);
});

app.listen(3000, () => {
  console.log(‘API disponível na porta 3000’);
});

1. require(‘express’) importa o framework instalado pelo NPM.

2. express() cria a aplicação.

3. express.json() permite interpretar corpos de requisição em JSON.

4. app.get cria uma rota de consulta.

5. app.post cria uma rota de inclusão.

6. res.status(201) indica criação bem-sucedida.

7. app.listen inicia o servidor na porta 3000.

Programação assíncrona com arquivos

O módulo fs oferece versões assíncronas e síncronas de várias operações. fs.readFile recebe uma função de callback e não bloqueia o event loop enquanto aguarda a leitura. Já fs.readFileSync bloqueia a thread até o término da operação e retorna o resultado diretamente. As duas funções podem ler o mesmo arquivo, mas não são “totalmente equivalentes”, pois possuem comportamentos, assinaturas e efeitos diferentes.

Leitura assíncrona de arquivo

const fs = require(‘fs’);

console.log(‘Início’);

fs.readFile(‘dados.txt’, ‘utf8’, (erro, conteudo) => {
  if (erro) {
    console.error(‘Falha na leitura:’, erro.message);
    return;
  }

  console.log(conteudo);
});

console.log(‘Fim’);

1. A primeira linha importa o módulo fs.

2. A mensagem Início é exibida imediatamente.

3. readFile inicia a leitura sem bloquear a thread principal.

4. Quando a leitura termina, o callback recebe erro ou conteúdo.

5. O return encerra o callback em caso de falha.

6. A mensagem Fim normalmente aparece antes do conteúdo do arquivo, porque a leitura é assíncrona.

Callbacks e callback hell

Callback é uma função passada para outra função para ser executada posteriormente. Esse padrão é comum em operações assíncronas. O problema aparece quando vários callbacks ficam aninhados, formando o chamado callback hell ou “pirâmide da perdição”. O código passa a crescer para a direita, fica difícil de ler e complica o tratamento de erros.

Promises

Uma Promise representa o resultado futuro de uma operação. Ela pode estar pendente, resolvida com sucesso ou rejeitada. Em JavaScript, esses estados são chamados pending, fulfilled e rejected. O método then() trata o sucesso; catch() trata a rejeição; 

Promises permitem encadear operações assíncronas de maneira mais organizada que callbacks aninhados. Mesmo assim, é importante tratar rejeições. Uma Promise rejeitada sem tratamento pode gerar avisos ou encerrar o processo, dependendo do contexto e da configuração.

Async e await

async/await é uma sintaxe construída sobre Promises. Uma função declarada com async sempre retorna uma Promise. A palavra await pausa apenas a execução daquela função assíncrona até a Promise ser concluída; ela não bloqueia a thread principal nem elimina o event loop.

O tratamento de erros costuma ser feito com try/catch, mas ele não é a única possibilidade. Uma função async também pode ter sua Promise tratada com .catch() por quem a chamou. Por isso, questões que afirmam que try/catch é obrigatoriamente a única forma de tratamento devem ser analisadas com cuidado.

Async/await com tratamento de erro

function buscarDados() {
  return Promise.resolve({ nome: ‘Padawan’ });
}

async function executar() {
  try {
    const dados = await buscarDados();
    console.log(dados.nome);
  } catch (erro) {
    console.error(‘Erro:’, erro.message);
  } finally {
    console.log(‘Processo finalizado’);
  }
}

executar();

1. buscarDados retorna uma Promise resolvida.

2. A palavra async faz executar retornar uma Promise.

3. await aguarda o resultado dentro da função executar.

4. try contém o código que pode falhar.

5. catch trata uma rejeição ou exceção.

6. finally executa ao final, com sucesso ou erro.

Bancos de dados

Node.js pode acessar bancos de dados por meio de drivers, bibliotecas, query builders ou ORMs instalados pelo NPM. Exemplos comuns são pg para PostgreSQL, mysql2 para MySQL, mssql para SQL Server, sqlite3 ou better-sqlite3 para SQLite e mongodb ou mongoose para MongoDB.

JavaScript não possui palavras-chave SQL nativas executadas diretamente pelo V8. A aplicação envia strings SQL por meio de uma biblioteca. Drivers modernos normalmente permitem iniciar transações e controlar operações como COMMIT e ROLLBACK.

Eventos e EventEmitter

O módulo events fornece a classe EventEmitter. Um objeto emissor dispara eventos com emit(), e funções ouvintes são registradas com on() ou addListener(). O método once() registra um listener que será executado apenas uma vez.

Listeners específicos podem ser removidos com removeListener() ou off(). removeAllListeners() remove vários ouvintes. Um detalhe importante é o evento error: quando um EventEmitter emite error sem listener registrado, o processo pode ser encerrado. Por isso, tratar esse evento é uma prática essencial.

Evento personalizado

const EventEmitter = require(‘events’);

const emissor = new EventEmitter();

emissor.on(‘mensagem’, (texto) => {
  console.log(‘Recebido:’, texto);
});

emissor.emit(‘mensagem’, ‘Que a força esteja com você!’);

1. O módulo events fornece a classe EventEmitter.

2. new EventEmitter() cria o objeto emissor.

3. on registra um listener para o evento mensagem.

4. emit dispara o evento e envia o texto ao listener.

Conclusão

Node.js amplia o uso do JavaScript para além do navegador e se destaca pelo modelo orientado a eventos, pelo I/O não bloqueante e pela integração entre V8, event loop e Libuv. Para concursos, aprenda as responsabilidades de cada componente, entenda a diferença entre operações síncronas e assíncronas, domine NPM, módulos, Express, Promises, async/await e EventEmitter. Com esses fundamentos, você consegue enfrentar tanto questões conceituais quanto itens baseados em código.

Hora de testar nosso conhecimento!

COMPERVE/UFRN – 2024 – UFERSA – Analista de Tecnologia da Informação

 O Node.js é uma plataforma de execução de código JavaScript. Essa plataforma permite que desenvolvedores utilizem esse código para criar aplicações de rede escaláveis e de alto desempenho. Analise as afirmativas:

I. É um ambiente de execução assíncrono.
II. Utiliza o V8 JavaScript engine.
III. É um ambiente de execução de código JavaScript do lado cliente.
IV. Utiliza o NPM para gerenciamento de memória.

Das afirmativas, estão corretas:

A) I e II.

B) I e IV.

C) II e III.

D) III e IV.

Gabarito: A) I e II.

Justificativa:

A) Correta. I é verdadeira porque Node.js possui modelo assíncrono; II é verdadeira porque utiliza o motor V8.

B) Incorreta. I é verdadeira, mas IV é falsa: NPM gerencia pacotes e scripts, não a memória da aplicação.

C) Incorreta. II é verdadeira, mas III é falsa: Node.js executa JavaScript fora do navegador, normalmente no servidor ou em ferramentas locais.

D) Incorreta. III e IV são falsas.

FUMARC – 2023 – AL-MG – Analista Legislativo – Analista de Sistemas I

 Analise as afirmativas referentes ao Node.js:

I. Permite executar aplicações JavaScript em uma máquina sem depender de navegador web.
II. Possui arquitetura assíncrona que trabalha com uma única thread de execução do código JavaScript.
III. Foi desenvolvido na linguagem Java e apresenta as principais características de orientação a objetos dessa linguagem.

Estão corretas as afirmativas:

A) I e II, apenas.

B) I e III, apenas.

C) II e III, apenas.

D) I, II e III.

Gabarito: A) I e II, apenas.

Justificativa:

A) Correta. I descreve a execução fora do navegador e II corresponde ao modelo padrão de uma thread principal para o JavaScript.

B) Incorreta. A afirmativa III é falsa: Node.js não é uma tecnologia desenvolvida em Java nem herda as características dessa linguagem.

C) Incorreta. II é verdadeira, mas III é falsa.

D) Incorreta. A presença da afirmativa III torna a combinação errada.

IBFC – 2022 – MGS – Desenvolvedor Front-End Java

 Considere as afirmativas sobre Node.js:

I. Utiliza programação assíncrona.
II. Pode manipular arquivos no cliente.
III. Pode manipular arquivos no servidor.

Está correto o que se afirma em:

A) I e II, somente.

B) I e III, somente.

C) I, II e III.

D) I, somente.

E) II e III, somente.

Gabarito: B) I e III, somente.

Justificativa:

A) Incorreta. I é verdadeira, mas II é falsa no sentido cobrado: o módulo fs atua no ambiente Node.js, e não no navegador do cliente.

B) Correta. Node.js trabalha com programação assíncrona e pode manipular arquivos no servidor.

C) Incorreta. A afirmativa II invalida a combinação.

D) Incorreta. A afirmativa III também é verdadeira.

E) Incorreta. II é falsa e I é verdadeira.

Quadrix – 2018 – CRM-PR – Programador de Tecnologia da Informação

 O Node é um interpretador da linguagem JavaScript, de código aberto, que possibilita a execução de códigos da linguagem do lado do servidor.

Gabarito: Certo.

Justificativa:

Em linguagem de prova, a descrição é aceita: Node.js é um ambiente open source que executa JavaScript no servidor. Tecnicamente, o V8 combina interpretação e compilação JIT, por isso “ambiente de execução” é uma expressão mais precisa que “interpretador”.

CESPE/CEBRASPE – 2024 – MPO – Analista de Planejamento e Orçamento

 A execução do Node.js é single-thread, pois as requisições no ambiente são tratadas como eventos assíncronos e não bloqueáveis.

Gabarito: Certo, no modelo padrão cobrado em prova.

Justificativa:

O código JavaScript é executado por padrão em uma thread principal, enquanto o ambiente trata I/O de forma assíncrona e não bloqueante. A afirmação é uma simplificação: Libuv, sistema operacional e worker threads podem usar outras threads.

Quadrix – 2025 – CREMESE – Analista de Sistemas

 JavaScript é uma linguagem de programação interpretada que pode ser executada tanto no cliente, em um navegador, quanto no servidor, com Node.js.

Gabarito: Certo.

Justificativa:

No navegador, JavaScript implementa comportamento do lado cliente; com Node.js, pode executar lógica de servidor, APIs, automações e acesso a recursos do sistema.

FGV – 2024 – TRF da 1ª Região – Analista Judiciário – Análise de Sistemas

 O Event Loop do Node.js, usado para gerenciar eventos e operações de entrada e saída assíncronas, tem sua implementação baseada principalmente:

A) no interpretador Chrome V8.

B) na biblioteca Libuv.

C) no gerenciador NPM.

D) na Core API do JavaScript.

E) no gerenciador Yarn.

Gabarito: B) na biblioteca Libuv.

Justificativa:

A) Incorreta. V8 executa o JavaScript, mas não é a biblioteca responsável pela implementação do event loop do Node.js.

B) Correta. Libuv fornece o event loop e recursos de I/O assíncrono multiplataforma.

C) Incorreta. NPM gerencia pacotes e scripts.

D) Incorreta. A linguagem JavaScript, por si só, não fornece a infraestrutura de sistema operacional usada pelo event loop.

E) Incorreta. Yarn é outro gerenciador de pacotes.

FUNDATEC – 2023 – PROCERGS – Analista em Computação

 Julgue as assertivas sobre Node.js:

1. Permite executar JavaScript do lado do servidor, fora do navegador.
2. A arquitetura orientada a eventos limita sua capacidade de lidar com muitas conexões simultâneas e baixo consumo de recursos.
3. É um ambiente assíncrono e não bloqueante, delegando processos demorados.
4. Possui o gerenciador de pacotes NPM.

A sequência correta é:

A) F – V – F – V.

B) V – F – V – V.

C) V – V – F – F.

D) V – F – F – V.

E) F – F – V – V.

Gabarito: B) V – F – V – V.

Justificativa:

A) Incorreta. A primeira afirmativa é verdadeira e a terceira também.

B) Correta. A sequência é V, F, V, V.

C) Incorreta. A segunda é falsa, enquanto a terceira e a quarta são verdadeiras.

D) Incorreta. A terceira é verdadeira.

E) Incorreta. A primeira é verdadeira.


Quer ficar por dentro dos concursos públicos abertos e previstos pelo Brasil? Clique nos links abaixo:

CONCURSOS FEDERAIS

CONCURSOS 2026

CONCURSOS ABERTOS

QUESTÕES DE CONCURSOS

Receba gratuitamente no seu celular as principais notícias do mundo dos concursos. Clique no link abaixo e inscreva-se:

WHATSAPP

TELEGRAM

Por
Publicado em
10 min. de leitura

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *