Como o JavaScript funciona?

Créditos ao artigo original (em inglês) que também fez os lindos GIFs de exemplo!

Inrodução 🤖

JavaScript tem seus problemas, mas ainda é uma linguagem que todo mundo ama odiar! Mas por trás dessa linguagem "simples", existe um sistema um tanto complexo que converte seu código simples em instruções para o computador. Por sorte, a engine V8 (usada no Node e navegadores que usam Chromium) é open-source, então podemos ver como tudo funciona por de baixo das linhas de código! V8

1. Carregamento

O parser de HTML primeiro encontra uma tag <script> com um código-fonte. O código dessa fonte é então carregado pela network, cache, ou em um service worker instalado. A resposta é o script requisitado em forma de um stream de bytes, que é cuidado pelo decodificador de bytes! O byte stream decoder decodifica o stream de bytes enquanto é feito o download!

GIF Carregamento

2. Tokens

O decodificador de byte stream cria tokens da stream de bytes decodificada. Por exemplo: 0066 -> f 0075 -> u 006e -> n 0063 -> c 0074 -> t 0069 -> i 006f -> o 006n -> n

Seguido por um espaço em branco, você escreveu function! Essa é uma keyword reservada pelo JavaScript. Um token é criado, e é enviado pro parser. (e pré-parser, que não aparece nos gifs mas é mostrado depois). O mesmo acontece pro resto da stream de bytes.

GIF Tokens

3. Parser

O V8 usa dois parsers: o pre-parser e o parser. Para reduzir o tempo que leva para carregar um website, a engine tenta evitar ler código que não é necessário no momento. O pre-parser cuida do código que talvez seja usado depois, enquanto o parser fica com o código que é imediatamente necessário! Se uma certa função só vai ser invocada depois de alguns cliques do usuário, não é necessário que esse código seja compilado imediatamente na hora de carregar o website. Se o usuário eventualmente acaba clicando no botão, o código necessário é enviado pro parser.

O parser cria nós baseados nos tokens que recebe do decodificador de byte stream. Com esses nós, ele cria uma Abstract Syntact Tree, ou AST. 🌳

GIF Parser

4. Interpretador

Agora é hora do interpretador! O interpretador anda por toda a AST, e gera byte code baseado na informação que a AST contém. Quando o byte code é completamente gerado, a AST é deletada para limpar a memória. E finalmente, temos algo que a máquina consegue usar para trabalhar! 🎉

GIF Interpreter

5. Otimização

Mesmo byte code sendo rápido, ele pode ser ainda mais veloz. Enquanto o byte code é executado, informação vai sendo gerada. Ele pode detectar quando um certo tipo de comportamento acontece frequentemente, e o tipo de dados que está sendo usado. Talvez você invoque uma função dezena de vezes: é hora de otimizar isso para ele executar ainda mais rápido! 🏃🏽‍

O byte code, junto com um feedback de tipo gerado, são enviados para um compilador de otimização. O compilador de otimização pega esse byte code e feedback de tipo, e gera um código de máquina altamente otimizado com eles. 🚀

GIF Optimizing

JavaScript é uma linguagem de tipagem dinâmica, o que significa que o tipo dos dados podem mudar constantemente. Seria extremamente lento se a engine do JS tivesse que checar toda vez qual o tipo de dado que um valor possui.

Para reduzir o tempo que leva para interpretar o código, código de máquina otimizado só cuida dos casos que a engine já viu antes enquanto executava o byte code. Se nós repetidamente usamos uma certa peça de código que retorna o mesmo tipo de dado sempre, o código de máquina otimizado pode simplesmente ser reusado para acelerar as coisas!

No entanto, como JavaScript é dinâmicamente tipado, pode acontecer que o mesmo pedaço de código de repente retorne um tipo de dado diferente. Se isso acontece, o código de máquina é "desotimizado", e a engine volta a interpretar o byte code gerado.

Digamos que uma certa função é invocada 100 vezes e sempre retornou o mesmo valor até o momento. Ele vai assumir que ela vai também retornar esse valor na 101º vez que você invocá-la.

Vamos dizer que temos a seguinte função sum, que (até o momento) sempre foi chamada com valores numérios como argumentos toda vez:

GIF Sum Code Example

Isso retorna o número 3! Na próxima vez que invocarmos ela, ele vai assumir que estamos invocando novamente com dois valores numéricos.

Se isso realmente acontecer, nenhuma verificação dinâmica é necessária, e ele pode só re-usar o código de máquina otimizado. Caso contrário, ele vai reverter para o byte code original ao invés do código de máquina otimizado.

Por exemplo, na próxima vez que invocarmos ela, passamos uma string no lugar de um número. Como JavaScript é dinâmicamente tipado, podemos fazer isso sem nenhum erro!

GIF Dynamic Code Example

Isso significa que o número 2 vai ser juntado à string, e a função vai retornar "12" no lugar. Ele volta a executar o byte code interpretado e atualiza o feedback de tipo.

Finalização!

Espero que tenham gostado e achado útil esse conteúdo! Existem várias partes que não foram cobertas no artigo (JS heap, call stack, etc.), se gostar, considere pesquisar sobre e talvez criar um conteúdo no TabNews explicando também!

Leiam o artigo original também se souberem inglês.

Lembrando que o V8 é open source, então você pode analisar o código diretamente se preferir!

E meus parabéns pelo artigo, obrigado por trazer um conteúdo tão completo e detalhado em português. Queria dizer que achei essa parte interessante. Nunca tinha parado para pensar nisso:

Seria extremamente lento se a engine do JS tivesse que checar toda vez qual o tipo de dado que um valor possui.

Fiquei com uma dúvida também: Existe alguma linguagem interpretada com tipagem estática? Seria algo teoricamente possível?

Pesquisando sobre não encontrei nenhuma linguagem realmente útil que tenha tipagem estática e seja interpretada, mas achei no Github [essa linguagem aqui](https://github.com/Pierre-vh/Fox) que é interpretada e estática! O projeto tá parado pelo que parece, mas é interessante

Excelente artigo, queria ter paciencia pra ler o codigo da V8 todinho rs.

Excelente Explicação, obrigado por compartilhar, JS é uma das linguagens que ainda quero me aprofundar, seria da hora se o deschamps produzisse um curso de JS pra devs iniciantes assim como eu ...

Excelente artigo.