O Event Loop do Node.js: O que é e como funciona

O Event Loop do Node.js: O que é e como funciona
AdsTerra, Junte-se ao AdsTerra

O Node.js é uma plataforma de desenvolvimento de aplicações web baseada no JavaScript, que permite criar programas que executam de forma assíncrona e não bloqueante. Isso significa que o Node.js pode lidar com várias operações simultaneamente, sem esperar que uma termine para iniciar outra. Mas como isso é possível? A resposta está no event loop, um mecanismo que gerencia o fluxo de execução do código e os eventos que ocorrem no sistema.

O que é um evento?

Um evento é algo que acontece em um determinado momento, como por exemplo, um clique do usuário, uma requisição HTTP, uma leitura ou escrita de um arquivo, um timer que expira, etc. Esses eventos são gerados por diferentes fontes, como elementos HTML, objetos globais do navegador, módulos do Node.js, etc. Cada evento pode ter uma ou mais funções associadas, chamadas de callbacks, que são executadas quando o evento ocorre.

O que é o event loop?

O event loop é um loop infinito que roda em uma única thread, ou seja, um único fluxo de execução. Ele é responsável por verificar se há eventos na fila, retirá-los e enviá-los para a pilha de chamadas, onde as funções callback são executadas. O event loop também interage com outras threads, chamadas de workers, que executam operações de entrada e saída (I/O) de forma assíncrona e não bloqueante. Essas operações podem ser, por exemplo, acessar o banco de dados, o sistema de arquivos, a rede, etc. Quando uma operação de I/O é concluída, ela gera um evento e coloca o callback na fila de retorno de chamada, que será processada pelo event loop.

Como funciona o event loop?

O event loop segue um ciclo que consiste em seis fases principais:

  1. Timers: Nessa fase, o event loop verifica se há timers que expiraram, ou seja, funções que foram agendadas para serem executadas depois de um determinado tempo com os métodos setTimeout ou setInterval. Se houver, o event loop retira o timer da fila e coloca o callback na pilha de chamadas.
  2. I/O callbacks: Nessa fase, o event loop executa os callbacks de operações de I/O que foram concluídas anteriormente, exceto os que estão relacionados a streams, TCP ou UDP. Esses callbacks são colocados na fila de retorno de chamada pelos workers que realizam as operações de I/O de forma assíncrona.
  3. Idle, prepare: Essa fase é usada internamente pelo Node.js e não tem relevância para o desenvolvedor.
  4. Poll: Nessa fase, o event loop verifica se há novos eventos de I/O, como requisições HTTP, conexões TCP, leitura ou escrita de arquivos, etc. Se houver, o event loop retira o evento da fila e coloca o callback na pilha de chamadas. Essa fase é a mais longa do ciclo, pois o event loop espera até que haja pelo menos um evento na fila ou que um timer expire.
  5. Check: Nessa fase, o event loop verifica se há callbacks que foram agendados com o método setImmediate. Se houver, o event loop retira o callback da fila e coloca na pilha de chamadas.
  6. Close callbacks: Nessa fase, o event loop executa os callbacks que estão relacionados ao fechamento de sockets, streams ou outros recursos. Esses callbacks são registrados com o método on('close', callback).

Após completar as seis fases, o event loop volta para a primeira fase e repete o ciclo. O event loop só termina quando não há mais eventos na fila e nem callbacks na pilha de chamadas.

Como visualizar o event loop?

Um exemplo de código para visualizar o event loop do Node.js é o seguinte:

// Importa o módulo fs para ler arquivos
const fs = require('fs');

// Define uma função assíncrona que lê um arquivo e imprime seu conteúdo
async function readFile(fileName) {
  // Usa o método fs.promises.readFile para ler o arquivo de forma assíncrona
  // e retorna uma promessa que será resolvida com o conteúdo do arquivo
  const data = await fs.promises.readFile(fileName, 'utf8');
  // Imprime o conteúdo do arquivo
  console.log(data);
}

// Define uma função assíncrona que usa o método setTimeout para agendar uma função
// para ser executada depois de um determinado tempo
async function delay(time) {
  // Retorna uma promessa que será resolvida depois de time milissegundos
  return new Promise((resolve) => {
    // Usa o método setTimeout para agendar a função resolve para ser executada
    // depois de time milissegundos
    setTimeout(resolve, time);
  });
}

// Define uma função assíncrona que usa o método process.nextTick para agendar uma função
// para ser executada na próxima iteração do event loop
async function nextTick() {
  // Retorna uma promessa que será resolvida na próxima iteração do event loop
  return new Promise((resolve) => {
    // Usa o método process.nextTick para agendar a função resolve para ser executada
    // na próxima iteração do event loop
    process.nextTick(resolve);
  });
}

// Define uma função assíncrona que usa o método setImmediate para agendar uma função
// para ser executada na fase de check do event loop
async function immediate() {
  // Retorna uma promessa que será resolvida na fase de check do event loop
  return new Promise((resolve) => {
    // Usa o método setImmediate para agendar a função resolve para ser executada
    // na fase de check do event loop
    setImmediate(resolve);
  });
}

// Chama as funções assíncronas definidas acima e imprime algumas mensagens
// para mostrar a ordem de execução das funções e dos callbacks
console.log('Início');

readFile('file.txt')
  .then(() => {
    console.log('Leitura do arquivo concluída');
  })
  .catch((error) => {
    console.error('Erro ao ler o arquivo:', error);
  });

delay(1000)
  .then(() => {
    console.log('Delay de 1 segundo concluído');
  })
  .catch((error) => {
    console.error('Erro ao agendar o delay:', error);
  });

nextTick()
  .then(() => {
    console.log('Next tick concluído');
  })
  .catch((error) => {
    console.error('Erro ao agendar o next tick:', error);
  });

immediate()
  .then(() => {
    console.log('Immediate concluído');
  })
  .catch((error) => {
    console.error('Erro ao agendar o immediate:', error);
  });

console.log('Fim');

Esse código usa o módulo fs para ler um arquivo de forma assíncrona, o método setTimeout para agendar uma função para ser executada depois de um determinado tempo, o método process.nextTick para agendar uma função para ser executada na próxima iteração do event loop, e o método setImmediate para agendar uma função para ser executada na fase de check do event loop. O código também imprime algumas mensagens no console para mostrar a ordem de execução das funções e dos callbacks.

Podemos ver que o event loop começa na fase de timers e verifica se há algum timer que expirou. Como não há, ele passa para a próxima fase, que é a de I/O callbacks. Nessa fase, ele também não encontra nenhum callback para executar, então ele passa para a fase de idle, prepare, que é interna. Em seguida, ele chega na fase de poll, onde ele verifica se há novos eventos de I/O. Como não há, ele fica esperando até que um timer expire ou que um evento de check ou close ocorra. Enquanto isso, o código síncrono é executado na pilha de chamadas, imprimindo as mensagens “Início” e “Fim”.

Depois disso, o método process.nextTick coloca o callback na fila de retorno de chamada, que é processada antes de qualquer outra fase. O callback é executado e imprime a mensagem “Next tick concluído”. Em seguida, o método setImmediate coloca o callback na fila de check, que é processada na fase de check do event loop. O event loop sai da fase de poll e entra na fase de check, onde ele retira o callback da fila e coloca na pilha de chamadas. O callback é executado e imprime a mensagem “Immediate concluído”. O event loop continua o ciclo e chega novamente na fase de poll, onde ele espera até que o timer expire. Depois de 1 segundo, o timer expira e coloca o callback na fila de retorno de chamada. O event loop sai da fase de poll e entra na fase de timers, onde ele retira o callback da fila e coloca na pilha de chamadas. O callback é executado e imprime a mensagem “Delay de 1 segundo concluído”. O event loop continua o ciclo e chega novamente na fase de poll, onde ele verifica se há novos eventos de I/O. Nesse momento, a operação de leitura do arquivo é concluída e coloca o callback na fila de retorno de chamada. O event loop retira o callback da fila e coloca na pilha de chamadas. O callback é executado e imprime o conteúdo do arquivo e a mensagem “Leitura do arquivo concluída”. O event loop termina o ciclo e verifica que não há mais eventos na fila nem callbacks na pilha de chamadas, então ele encerra a execução.

Conclusão

Neste artigo, vimos o que é o event loop do Node.js, um mecanismo que permite que o Node.js execute código de forma assíncrona e não bloqueante, lidando com vários eventos simultaneamente. Vimos também como o event loop funciona, quais são as fases do seu ciclo e como visualizá-lo com uma ferramenta interativa. Espero que este artigo tenha sido útil para você entender melhor o funcionamento do Node.js e como escrever código mais eficiente e escalável.

Sugestões de cursos

Descubra o caminho para se tornar um especialista em programação web. Aprenda HTML, CSS, JavaScript e os principais frameworks nesta jornada emocionante. Com instrutores experientes e materiais práticos, você desenvolverá habilidades práticas para criar sites impressionantes e aplicativos interativos. Impulsione sua carreira na indústria de tecnologia e abra portas para oportunidades de emprego lucrativas. Garanta sua vaga hoje mesmo e inicie sua jornada para se tornar um desenvolvedor web de sucesso.

Método Para Aprender a Programar do Absoluto ZERO com Node.js, React e React Native.

Curso de Node.js, React e React Native

As tecnologias ensinadas no curso são responsáveis por muitas vagas no mercado de trabalho.

Além da alta demanda, os salários vão de R$47.000,00 até R$197.000,00 anuais tendo empresas que possibilitam o trabalho remoto e até vagas Internacionais.

Para que você possa estar apto a preencher uma dessas vagas eu vou te apresentar o passo a passo para você se tornar um verdadeiro expert nessas tecnologias.

O curso te dará o passo a passo de como criar estruturar de um sistema do zero com Node.js, React e React Native.

Saiba mais sobre o curso de Node.js, React e React Native.

AdsTerra, Junte-se ao AdsTerra