deividy@blog:~

Funcionamento interno do NodeJS

06/02/2018

Event loop? V8? Single Thread? JavaScript server side? O que diabos é isso?

Funcionamento interno do NodeJS


NodeJS é uma camada em cima de uma virtual machine chamada V8 (cool name, huh?), então antes de entendermos o que é o NodeJS vamos entender um pouco sobre a historia do V8.


No inicio da web, por volta de 1995, nasceu o JavaScript, ele foi criado em apenas 10 dias pelo Brendan Eich, programador do Netscape na época, só começou a ser padronizado 2~ anos depois (o nascimento do ECMAScript).
Seu primeiro nome foi Mocha, depois LiveScript e só então se tornou o JavaScript.



O primeiro compilador JavaScript se chamava SpiderMonkey (existe até hoje!), foi desenvolvido para o navegador Netscape, e era um simples interpretador que lia e executava códigos JavaScript, durante um bom tempo JavaScript foi praticamente um filho bastardo, ninguém deu muita atenção e basicamente servia apenas para enviar formulários e abrir popups. (haha .)
Cerca de dez anos depois de seu nascimento o Google lançou o Google Maps, powered por JavaScript, na época, como JavaScript era terra de ninguém, sofreu a funcionar em varios browsers, e muitos artigos sobre padrões de compilar JavaScript surgiram, o processo de compilar era super simples, e a partir daí começaram a olhar com outros olhos para o nosso JS.



Só em 2008 o Google lançou sua arma open-source, chamada Chrome V8 (ou só V8 pros chegado), a idéia era padronizar um compilador JS e "bombar" o seu novo browser.
O V8 funciona com varias threads internas, como por ex a main thread que basicamente lê um código, manda para outra thread que compila o seu código e quando ele estiver pronto volta para main thread e executa.
Essa thread que compila o código basicamente aplica varias optimizações, existem pelo menos dois processos de compilação que rodam em paralelo (Full-Codegen e Crankshaft) e produz algo pronto para ser executado em machine code, além disso tem pelo menos mais duas threads rodando, que são a de garbage collector e dead code elimination.
(Como o V8 cuida de processar e transformar o código vou deixar para outro post...)



Resumidamente, o V8 processa códigos JavaScript. Pelo seguinte processo: ele começa a processar o seu código, manda para outra thread compilar, e a thread principal fica aberta para novos processamentos até ter sua resposta de volta, e só quando seu código termina de compilar ela volta a processar ele.



OK, faz sentido... e o NodeJS?
Calma, calma! Vamos chegar lá... temos que falar um pouco sobre a libev (ou libevent) e o Microsoft IOCP.
Esse vai ser bem rápido, pois não tenho muita historia pra eles :P
Basicamente, essas duas libraries fornecem uma API para executar funções quando determinados eventos ou timeouts acontecerem, libev para UNIX e IOCP para Windows.



Huum.. to começando a entender, o V8 processa o JavaScript e a libev/IOCP chamam meus callbacks no Node quando terminar?
Quase isso! A libev/IOCP estão meio que deprecated theses days, delas nasceu a libuv que é o que o NodeJS usa no momento.



Continuando... em 2009 Ryan Dahl juntou essas duas tecnologias para criar o NodeJS.
Basicamente, o V8 processa o JS, transforma em machine code, a libuv manda executar e anexa um callback a isso, quando pronto, chama esse callback que retorna pra userland.
Esse vai e volta é o chamado Event Loop, ou IO não bloqueante do NodeJS. Quando escrevemos um código ou script para NodeJS o event loop pega esse código, processa ele, manda para a libuv e vai atrás de mais códigos para mandar pro v8 e para a libuv, e assim vai.



Mas peraí, ouvi dizer que NodeJS é single thread...
Isso! Você está correto (em partes). Pois, NodeJS mantém uma única thread aberta para o seu codigo, um EventLoop na libuv (não é o NodeJS de fato que tem o event loop, ele cria e gerencia um na libuv).



Achei essa imagem que representa bem esse flow:


Event loop NodeJS

Refs:



Fez algum sentido? :)