Nota do editor: este artigo foi atualizado em 6 de maio de 2021.
Sempre que ouço pessoas discutirem Node.js , surgem muitas perguntas sobre o que é exatamente , para que serve esta tecnologia e se há um futuro para isso.
O que é Node.js?
Vamos tentar abordar a primeira parte. A maneira mais fácil de responder a essa pergunta seria listar muitas definições do que o Node é tecnicamente:
- Node.js é um ambiente de tempo de execução JavaScript construído no motor V8 JavaScript do Chrome
- Node.js usa um modelo de E/S não bloqueador e orientado por eventos que o torna leve e eficiente
- O ecossistema de pacotes de nós (npm) é o maior ecossistema de bibliotecas de código aberto em todo o mundo
Mas, ainda assim, todas essas respostas não me satisfazem; há algo faltando. Depois de ler os pontos acima, você pode pensar no Node.js como apenas outra tecnologia JavaScript, mas a parte mais importante de entendê-lo é analisar como ele pode ser assíncrono e ter um sistema de E/S totalmente sem bloqueio.
Isso é realmente o que o transformou em algo obrigatório para todos os desenvolvedores da web.
Entender exatamente como o Node funciona nos bastidores não só gerará um maior conhecimento dessa tecnologia, mas também criará tração para as pessoas que ainda não a usaram para mergulhar e começar a aprendê-la.
E para todas as pessoas que já são profissionais nesta área, compreender os seus detalhes irá transformá-lo num novo programador atualizado e totalmente equipado para melhorar o seu desempenho de acordo com as suas necessidades.
Então, para explorar o mundo do Node, examinaremos sua parte central: o loop de eventos , que, na verdade, é a parte responsável por seu I/O sem bloqueio modelo.
Uma breve atualização dos tópicos
Antes de mergulhar fundo no loop de eventos, gostaria de passar algum tempo nos tópicos . Se você está se perguntando por que isso é necessário, direi que, para entender melhor um conceito, devemos primeiro começar a formar um vocabulário em nossas mentes que nos ajudará a reconhecer cada parte de um sistema. Isso será uma grande vantagem ao ler mais tarde sobre o loop de eventos, como funciona e como o conceito de thread se aplica a ele.
Sempre que executamos um programa, criamos uma instância dele e, associado a essa instância, temos algo interno chamado threads . Um thread pode ser visto como uma unidade de operações que nossa CPU deve realizar por nós. Muitos threads diferentes podem ser associados a um único processo de um programa. Aqui está um gráfico para ajudá-lo a formar essa ideia em sua mente:
A parte mais importante para entender sobre os threads é: Como nossa máquina pode determinar qual thread processar em um determinado momento?
Como sabemos, nossas máquinas têm uma quantidade limitada de recursos (CPU, RAM), por isso é muito importante determinar corretamente onde vamos alocá-los ou, melhor, quais operações têm precedência sobre outras. E tudo isso tem que acontecer sem deixar de garantir que nenhuma operação leve muito tempo-ninguém gosta de um laptop lento.
O mecanismo usado para resolver o problema de alocação é denominado agendamento , e é gerenciado por nosso sistema operacional por uma entidade chamada agendador de SO. A lógica por trás disso pode ser muito complexa, mas para encurtar a história, podemos agrupar duas das principais maneiras pelas quais essa operação é realizada:
- Máquinas multi-core : atribuir threads diferentes a núcleos diferentes.
- Usar uma lógica de otimização que reduz os tempos mortos: esta é a abordagem mais relevante para nós. Se examinarmos mais de perto como os threads funcionam, veremos que nosso escalonador do sistema operacional pode reconhecer quando nossa CPU está esperando por algum outro recurso para realizar um trabalho, portanto, pode ser alocado para realizar outras operações nesse meio tempo. Isso geralmente acontece para operações de E/S muito caras, como leitura do disco rígido.
O que é um loop de evento em Node.js?
Agora que temos uma atualização saudável sobre como os threads funcionam, podemos finalmente abordar a lógica de loop de evento do Node.js . Ao ler isso, você entenderá a razão por trás da explicação anterior, e cada peça irá para o lugar certo sozinha.
Sempre que rodamos um programa Node, uma thread é criada automaticamente. Este thread é o único lugar onde toda a nossa base de código será executada. Dentro dele, algo chamado loop de evento é gerado. A função desse loop é agendar quais operações nosso único thread deve realizar em um determinado momento.
Observe que o loop de eventos não é gerado instantaneamente assim que executamos nosso programa. Na verdade, ele só é executado depois que todo o programa foi executado.
Simulando um loop de eventos Node.js
Agora vamos tentar simular como o loop de eventos funciona e o que ele faz para fazer nosso programa funcionar. Para fazer isso, vou fingir que estou alimentando o Node com um arquivo chamado myProgram
e, em seguida, entrarei em detalhes sobre o que o loop de eventos fará com ele.
Em particular, vou escrever primeiro uma breve explicação gráfica do que está acontecendo durante qualquer tick de loop de evento e, em seguida, vou explorar essas fases de uma maneira mais profunda.
Etapa 1: performChecks
Não preciso dizer que o loop de eventos é, na verdade, um loop. Isso significa que ele tem uma condição específica que determinará se o loop precisa iterar novamente ou não. Cada iteração do loop de evento é chamada de tick .
Quais são as condições para o loop de eventos realizar um tick?
Sempre que executamos nosso programa, teremos uma série de operações que precisam ser realizadas. Essas operações podem ser divididas em três tipos principais:
- Operações pendentes de temporizador (
setTimeout ()
,setInterval ()
,setImmediate ()
) - Tarefas pendentes do sistema operacional
- Execução pendente de operações de longa duração
Entraremos em mais detalhes sobre isso mais tarde; por enquanto, vamos apenas lembrar que sempre que uma dessas operações estiver pendente, o loop de eventos executará um novo tique.
Etapa 2: Executar um tique
Para cada iteração de loop, podemos distinguir as seguintes fases:
- Fase 1: o nó examina sua coleção interna de temporizadores pendentes e verifica quais funções de retorno de chamada foram passadas para
setTimeout ()
esetInterval ()
estão prontos para serem chamados em caso de expiração do cronômetro
- Fase 2: o Node examina sua coleção interna de tarefas pendentes do SO e verifica quais funções de retorno de chamada estão prontas para serem chamadas. Um exemplo disso poderia ser a recuperação completa de um arquivo do disco rígido de nossa máquina
- Fase 3: o nó pausa sua execução esperando que novos eventos ocorram. Com novos eventos, incluímos: uma nova conclusão do cronômetro, uma nova conclusão da tarefa do sistema operacional, uma nova conclusão da operação pendente
- Fase 4: o nó verifica se alguma função relacionada a temporizadores pendentes relacionados à função
setImmediate ()
está pronta para ser chamada
- Fase 5: gerenciar eventos de fechamento, usados para limpar o estado de nosso aplicativo
Perguntas e mitos comuns sobre o loop de eventos do Node.js
O Node.js é completamente single-threaded?
Este é um equívoco comum sobre essa tecnologia. O Node é executado em um único thread, mas algumas das funções incluídas na biblioteca padrão do Node.js não (as funções do módulo fs
, por exemplo); sua lógica é executada fora do thread único do Node.js. Isso é feito para preservar a velocidade e o desempenho de nossos programas.
Onde essas outras conversas são terceirizadas?
Ao usar Node.js, um módulo de biblioteca especial chamado libuv é usado para realizar operações assíncronas. Esta biblioteca também é usada, junto com a lógica posterior do Node, para gerenciar um pool de threads especial denominado pool de threads libuv .
Este pool de threads é composto por quatro threads usadas para delegar operações que são muito pesadas para o loop de eventos. As tarefas de longa execução mencionadas acima na lógica do loop de evento representam as operações descritas aqui como muito caras para o loop de evento.
Então, o loop de eventos é uma espécie de estrutura semelhante a uma pilha?
Nesse sentido, embora algumas estruturas semelhantes a pilhas estejam envolvidas no processo mencionado acima, uma resposta mais precisa seria que o loop de eventos é composto por uma série de fases, cada uma com suas próprias tarefas específicas, todas processadas em uma forma circular repetitiva. Para obter mais informações sobre a estrutura exata do loop de eventos, confira esta palestra .
Conclusão
Compreender o loop de eventos é uma parte vital do uso do Node.js, esteja você tentando obter mais informações sobre essa tecnologia, aprender como melhorar seu desempenho ou encontrar um novo e interessante motivo para aprender uma nova ferramenta.
Este guia deve ter ajudado você a explorar este assunto. Sinta-se à vontade para deixar um comentário abaixo, as opiniões e feedbacks são extremamente úteis para ajudar todos a aprender melhor.
A postagem Um guia completo para o O loop de eventos Node.js apareceu primeiro no LogRocket Blog .