Embora possa exigir uma compreensão profunda de linguagens como C++ e C para escrever código de produção em grande escala, o JavaScript pode ser escrito com apenas uma compreensão básica do que pode ser feito com a linguagem.
Conceitos, como passar callbacks para funções ou escrever código assíncrono, geralmente não são tão difíceis de implementar, o que faz com que a maioria dos desenvolvedores de JavaScript se importe menos com o que acontece nos bastidores. Eles simplesmente não se preocupam em entender as complexidades que os abstraíram profundamente pela linguagem.
Como desenvolvedor de JavaScript, torna-se cada vez mais importante entender o que realmente acontece nos bastidores e como a maioria dessas complexidades abstraídas de nós realmente funciona. Isso nos ajuda a tomar decisões mais informadas, o que pode, por sua vez, aumentar drasticamente o desempenho do nosso código.
Este artigo enfoca um dos conceitos ou termos muito importantes, mas raramente compreendidos, em JavaScript. O EVENTO LOOP!.
Escrever código assíncrono não pode ser evitado em JavaScript, mas por que um código rodando de forma assíncrona realmente significa? ou seja, o loop de eventos
Antes de entendermos como o loop de eventos funciona, primeiro precisamos entender o que é o próprio JavaScript e como ele funciona!
últimas postagens
O que é JavaScript?
Antes de prosseguirmos, gostaria que voltássemos ao básico. O que realmente é JavaScript? Poderíamos definir JavaScript como;
JavaScript é uma linguagem simultânea, assíncrona, assíncrona, interpretada, de alto nível e sem bloqueio.
Espere, o que é isso? Uma definição livresca? 🤔
Vamos quebrar isso!
As palavras-chave aqui em relação a este artigo são single-threaded, non-blocking, concorrente e assíncrono.
Fio único
Um thread de execução é a menor sequência de instrução programada que pode ser gerenciada independentemente por um escalonador. Uma linguagem de programação é de thread único, o que significa que ela só pode executar uma tarefa ou operação por vez. Isso significa que ele executaria um processo inteiro do início ao fim sem que o thread fosse interrompido ou parado.
Ao contrário das linguagens multiencadeadas, nas quais vários processos podem ser executados em vários encadeamentos simultaneamente sem bloquear uns aos outros.
Como o JavaScript pode ser de thread único e sem bloqueio ao mesmo tempo?
Mas o que significa bloquear?
Sem bloqueio
Não existe uma definição de bloqueio; simplesmente significa coisas que estão rodando lentamente no encadeamento. Portanto, não bloquear significa coisas que não são lentas no encadeamento.
Mas espere, eu disse que o JavaScript é executado em um único thread? E eu também disse sem bloqueio, o que significa que a tarefa é executada rapidamente na pilha de chamadas? Mas como??? Que tal quando executamos temporizadores? Rotações?
Relaxar! Iríamos descobrir daqui a pouco 😉.
Simultâneo
Simultaneidade significa que o código está sendo executado simultaneamente por mais de um thread.
Ok, as coisas estão ficando realmente estranhas agora, como o JavaScript pode ser single-threaded e concorrente ao mesmo tempo? ou seja, executando seu código com mais de um thread?
Assíncrono
Programação assíncrona significa que o código é executado em um loop de eventos. Quando há uma operação de bloqueio, o evento é iniciado. O código de bloqueio continua em execução sem bloquear o thread de execução principal. Quando o código de bloqueio termina de executar, ele enfileira o resultado das operações de bloqueio e os empurra de volta para a pilha.
Mas JavaScript tem um único thread? O que então executa esse código de bloqueio enquanto permite que outros códigos no thread sejam executados?
Antes de prosseguirmos, vamos recapitular o que foi dito acima.
- JavaScript é de thread único
- JavaScript não bloqueia, ou seja, processos lentos não bloqueiam sua execução
- JavaScript é concorrente, ou seja, executa seu código em mais de uma thread ao mesmo tempo
- O JavaScript é assíncrono, ou seja, executa o código de bloqueio em outro lugar.
Mas o que foi dito acima não bate exatamente, como uma linguagem de encadeamento único pode ser sem bloqueio, simultânea e assíncrona?
Vamos um pouco mais fundo, vamos até os mecanismos de tempo de execução do JavaScript, V8, talvez ele tenha alguns encadeamentos ocultos que não conhecemos.
Motor V8
O mecanismo V8 é um mecanismo de tempo de execução de montagem da Web de código aberto e de alto desempenho para JavaScript escrito em C++ pelo Google. A maioria dos navegadores executa JavaScript usando o mecanismo V8, e até mesmo o popular ambiente de tempo de execução node js também o utiliza.
Em inglês simples, o V8 é um programa C++, que recebe o código JavaScript, o compila e o executa.
O V8 faz duas coisas principais;
- Alocação de memória heap
- Contexto de execução da pilha de chamadas
Infelizmente, nossa suspeita estava errada. O V8 tem apenas uma pilha de chamadas, pense na pilha de chamadas como o thread.
Um thread === uma pilha de chamadas === uma execução por vez.
Imagem – Hacker Noon
Como o V8 tem apenas uma pilha de chamadas, como o JavaScript é executado simultaneamente e de forma assíncrona sem bloquear o thread de execução principal?
Vamos tentar descobrir escrevendo um código assíncrono simples, mas comum, e analisá-lo juntos.
O JavaScript executa cada código linha por linha, um após o outro (single-threaded). Como esperado, a primeira linha é impressa no console aqui, mas por que a última linha é impressa antes do código de tempo limite? Por que o processo de execução não espera pelo código de tempo limite (bloqueio) antes de prosseguir para executar a última linha?
Algum outro thread parece ter nos ajudado a executar esse tempo limite, pois temos certeza de que um thread pode executar apenas uma única tarefa a qualquer momento.
Vamos dar uma espiada no Código Fonte V8 por um tempo.
Espere o que??!!! Não há funções de timer no V8, nenhum DOM? Sem eventos? Sem AJAX?…. Eeeeeesss!!!
Eventos, DOM, temporizadores, etc. não fazem parte da implementação principal do JavaScript, o JavaScript está estritamente em conformidade com as especificações Ecma Scripts e várias versões dele são frequentemente referidas de acordo com suas especificações Ecma Scripts (ES X).
Fluxo de Trabalho de Execução
Eventos, cronômetros e solicitações Ajax são fornecidos no lado do cliente pelos navegadores e geralmente são chamados de API da Web. São eles que permitem que o JavaScript de thread único seja não-bloqueante, concorrente e assíncrono! Mas como?
Existem três seções principais no fluxo de trabalho de execução de qualquer programa JavaScript: a pilha de chamadas, a API da Web e a fila de tarefas.
A Pilha de Chamadas
Uma pilha é uma estrutura de dados na qual o último elemento adicionado é sempre o primeiro a ser removido da pilha, você pode pensar nisso como uma pilha de uma placa na qual apenas a primeira placa que foi a última adicionada pode ser removida primeiro. Uma Pilha de Chamadas nada mais é do que uma estrutura de dados de pilha onde as tarefas ou o código estão sendo executados de acordo.
Vamos considerar o exemplo abaixo;
Fonte – https://youtu.be/8aGhZQkoFbQ
Quando você chama a função printSquare() , ela é colocada na pilha de chamadas, a função printSquare() chama a função square(). A função square() é colocada na pilha e também chama a função multiple(). A função de multiplicação é colocada na pilha. Como a função de multiplicação retorna e é a última coisa que foi enviada para a pilha, ela é resolvida primeiro e removida da pilha, seguida pela função square() e depois pela função printSquare().
A API Web
É aqui que o código que não é tratado pelo mecanismo V8 é executado para não “bloquear” o thread de execução principal. Quando a Call Stack encontra uma função da API da web, o processo é imediatamente entregue à API da Web, onde está sendo executado e liberando a Call Stack para realizar outras operações durante sua execução.
Vamos voltar ao nosso exemplo setTimeout acima;
Quando executamos o código, a primeira linha console.log é enviada para a pilha e obtemos nossa saída quase imediatamente. Ao atingir o tempo limite, os cronômetros são manipulados pelo navegador e não fazem parte da implementação principal do V8, são enviados em vez disso, para a API da Web, liberando a pilha para que ela possa executar outras operações.
Enquanto o tempo limite ainda está em execução, a pilha avança para a próxima linha de ação e executa o último console.log, o que explica por que obtemos a saída antes da saída do cronômetro. Assim que o cronômetro é concluído, algo acontece. O console.log em seguida, o cronômetro aparece magicamente na pilha de chamadas novamente!
Como?
O Ciclo de Eventos
Antes de discutirmos o loop de eventos, vamos primeiro examinar a função da fila de tarefas.
De volta ao nosso exemplo de tempo limite, uma vez que a API da Web termina de executar a tarefa, ela não apenas a envia de volta para a pilha de chamadas automaticamente. Ele vai para a Fila de Tarefas.
Uma fila é uma estrutura de dados que funciona de acordo com o princípio Primeiro a Entrar, Primeiro a Sair, de modo que, conforme as tarefas são colocadas na fila, elas saem na mesma ordem. As tarefas que foram executadas pelas APIs da Web, que estão sendo enviadas para a fila de tarefas, voltam para a pilha de chamadas para obter o resultado impresso.
Mas espere. O QUE DIABOS É O LOOP DO EVENTO???
Fonte – https://youtu.be/8aGhZQkoFbQ
O loop de eventos é um processo que espera que a Pilha de Chamadas seja limpa antes de enviar retornos de chamada da Fila de Tarefas para a Pilha de Chamadas. Depois que a pilha é limpa, o loop de eventos é acionado e verifica a Fila de tarefas em busca de retornos de chamada disponíveis. Se houver algum, ele o envia para a Pilha de Chamadas, espera que a Pilha de Chamadas seja limpa novamente e repete o mesmo processo.
Fonte – https://www.quora.com/How-does-an-event-loop-work/answer/Timothy-Maxwell
O diagrama acima demonstra o fluxo de trabalho básico entre o loop de eventos e a fila de tarefas.
Conclusão
Embora esta seja uma introdução muito básica, o conceito de programação assíncrona em JavaScript fornece informações suficientes para entender claramente o que está acontecendo nos bastidores e como o JavaScript pode ser executado simultaneamente e de forma assíncrona com apenas um único thread.
O JavaScript está sempre sob demanda e, se você estiver curioso para aprender, aconselho que verifique este curso udemy.