‫Jonas: Agora vamos
‫escrever um código para entender melhor o
‫que acontece no loop de eventos.
‫Assim como antes, para começar
‫com a parte de codificação desta seção,
‫vá em frente e pegue os arquivos
‫iniciais para esta seção, copie-os em algum lugar
‫e, em seguida, abra o projeto em seu editor de código.
‫Então, eu o tenho aqui na área de
‫trabalho e no meu VSCode, e tudo o que temos aqui para
‫começar é este arquivo de teste. txt, então vou criar um novo arquivo aqui,
‫e vou chamá-lo de loop de evento. js.
‫Tudo bem, agora é extremamente difícil simular o loop
‫de evento corretamente, porque não podemos realmente
‫colocar muitos callbacks em todas as
‫filas de callback
‫que falamos antes, tudo ao mesmo tempo, certo.
‫Essa situação acontece quando, por
‫exemplo, muitas solicitações chegam ao seu
‫aplicativo, mas aqui localmente, isso é muito difícil de replicar.
‫Mas de qualquer forma, ainda faremos alguns experimentos
‫muito interessantes usando algumas das coisas
‫que aprendemos no último vídeo.
‫E o que vamos fazer é
‫escrever um monte de linhas de código
‫e, em seguida, tentar descobrir em que ordem elas
‫devem ser executadas no loop de eventos e analisar
‫se os resultados que obtemos realmente fazem sentido.
‫Então, vamos começar escrevendo um setTimeout,
‫basicamente, para definir um temporizador,
‫estou usando uma função de
‫seta aqui,
‫e a única coisa que farei é
‫registrar para console alguma string, então console. log, cronômetro um terminou, e
‫eu quero que isso expire logo após zero segundos.
‫Ok, salve, e então você verá que
‫ele realmente corrigiu essa string aqui, então
‫mudou as aspas e adicionou o ponto-e-vírgula, e isso
‫é por causa da
‫extensão mais Prettier que instalamos antes.
‫Agora não vou configurá-lo aqui,
‫porque para esse pequeno
‫exemplo, isso não é realmente necessário, ok.
‫Então isso é definir um cronômetro,
‫então vamos usar setImmediate, então lembre-se disso no último vídeo.
‫Ok, agora não vou explicar muito aqui, por
‫enquanto vamos escrever esse código
‫e depois analisar o que acontece, ok.
‫Portanto, setImmediate e, assim como o outro cronômetro, recebe uma função
‫de retorno de chamada.
‫E tudo o que vamos fazer é
‫escrever imediatamente um acabado, e esse aqui não tem
‫tempo, porque não é
‫necessário porque como o nome diz, é imediato.
‫Então outra coisa que queremos
‫fazer é ler este arquivo aqui, e então passar
‫uma função de retorno de chamada, ok, então a primeira
‫coisa é que temos que exigir o módulo correto, então FS, e
‫agora fs. readFile, e queremos um arquivo de texto. txt,
‫e então algo acontecerá.
‫E assim como antes, vamos apenas dizer
‫aqui, neste caso o I / O terminou, certo.
‫Então, I / O porque este retorno
‫de chamada aqui está realmente relacionado a uma tarefa de I / O,
‫que na verdade obtém sua própria fase no loop de eventos, certo.
‫E, finalmente, vamos adicionar um console. logar aqui, dizendo
‫bem, olá do código de nível superior.
‫Ok, e código de nível superior, porque é realmente o único
‫que não está dentro de nenhum retorno de chamada.
‫Portanto, neste pequeno exemplo que temos por agora, vamos
‫tentar descobrir o que deve acontecer primeiro.
‫Bem, lembre-se de que a primeira
‫etapa ao carregar um módulo é que seu
‫código de nível superior seja executado, portanto, imediatamente
‫devemos ver este console. log aqui, certo, só
‫então mais tarde devemos ver os outros logs
‫vindos desses outros callbacks, porque esses
‫callbacks vão realmente rodar no loop de eventos.
‫Então, vamos tentar ver se esse é realmente
‫o caso e, em seguida, analisar um pouco melhor ainda.
‫Abrindo o console aqui, e novamente, estou
‫fazendo isso usando o
‫terminal, ou realmente na visualização, então este terminal aqui, tudo bem.
‫Portanto, observe, evento-loop. js, ou na verdade antes
‫de fazermos isso, preciso corrigir esse erro de digitação aqui, então é um
‫arquivo de teste, não um arquivo de texto.
‫Ok, mas agora estamos prontos para executar
‫este comando e os resultados estão disponíveis, então o primeiro
‫log que temos aqui é oi do código de nível
‫superior, e isso era esperado, certo,
‫porque este é um código que é executado imediatamente.
‫Depois disso, temos essas três saídas, mas na verdade elas não estão
‫em uma ordem particular, e isso é porque esse
‫código aqui, então esse código, não
‫está realmente em um ciclo de E / S, então não
‫está sendo executado dentro do loop de eventos, porque
‫não está sendo executado dentro de nenhuma função de retorno de chamada.
‫Ok, então em seu computador, você pode realmente ver
‫este log aqui antes
‫deste, e este aqui é apenas
‫o último porque este tipo de arquivo aqui leva
‫algum tempo para ser lido e
‫provavelmente sempre será o último 1.
‫Então, novamente, neste ponto, a ordem desses três aqui não tem nada
‫a ver com o loop de eventos, porque
‫eles ainda não estão
‫executando dentro do loop de eventos.
‫Para isso, teremos que movê-los, ou pelo
‫menos mover esses dois aqui, dentro de uma função de callback.
‫E então, para isso, vamos usar este aqui, na verdade.
‫Deixe-me colocá-lo aqui, e dizer o temporizador dois e o temporizador dois
‫aqui, ou imediatamente dois, e também vou adicionar outro temporizador aqui, então o
‫temporizador três, e este vai
‫funcionar por três segundos, ou seja, 3.000 milissegundos .
‫Então, vamos agora tentar o resultado deste.
‫Mas antes de fazermos isso, vamos
‫realmente pensar por que logo depois que todo o código
‫anterior foi executado, o programa saiu e voltou para o prompt aqui.
‫Portanto, lembre-se de como o Node. js decide se deve
‫continuar executando o loop de eventos, bem, ele o
‫faz perguntando se ainda há algum tempo em execução
‫em segundo plano e, se for o caso, não terminará
‫e se ainda houver um temporizador pendente,
‫bem, então não é vai sair do programa.
‫Mas se não houver, que
‫era o caso no primeiro exemplo aqui, ele sai
‫imediatamente do programa, ok, mas agora temos um
‫temporizador aqui, então este funcionará por
‫três segundos, então vamos tentar descobrir o
‫que acontece aqui.
‫Ok, então você vê que ele
‫não está saindo, e só agora, depois que o
‫cronômetro três terminou, ele saiu do aplicativo.
‫Ok, então vamos ver isso de novo,
‫todos esses cronômetros de registros em execução, cronômetro
‫finalizado e, portanto, saiu do aplicativo.
‫Agora, sobre esses resultados aqui, vamos realmente
‫tornar isso aqui um pouco mais
‫fácil de ver e adicionar apenas um pequeno separador aqui.
‫Ok, limpe isso, ok.
‫Portanto, esses quatro aqui são as saídas que não
‫estavam realmente sendo executadas no loop de
‫eventos, mas esses três aqui estavam
‫realmente saindo do loop de eventos, então vamos agora analisar esses resultados.
‫Agora, se você
‫se lembrar do diagrama da aula anterior,
‫provavelmente terá pensado que o cronômetro, então o cronômetro dois aqui,
‫deveria realmente terminar antes do setImmediate,
‫porque no diagrama, ele realmente apareceu primeiro bem
‫no topo do loop de eventos.
‫Portanto, temos que definir o tempo limite
‫aqui com zero, que deve ser o mesmo que setImmediate, certo.
‫Então, por que
‫setImmediate realmente aparece antes de setTimeout?
‫Bem, há algo que eu realmente
‫não expliquei no último vídeo, porque não queria
‫torná-lo ainda mais confuso, e é que o loop de
‫eventos realmente espera que as coisas aconteçam na fase de votação.
‫Portanto, nessa fase em que os retornos de chamada de E / S são tratados.
‫Então, quando esta fila de retornos de chamada está vazia, que
‫é o caso em nosso exemplo fictício aqui, então
‫não temos retornos de chamada de E
‫/ S, tudo o que temos são esses temporizadores, bem, então
‫o loop de evento irá esperar nesta fase até que haja um expirado cronômetro.
‫Mas, se agendamos um retorno de chamada usando setImmediate,
‫esse retorno de chamada será executado imediatamente
‫após a fase de pesquisa
‫e mesmo antes de temporizadores expirados, se houver.
‫E, neste caso, o cronômetro expira imediatamente, portanto, após
‫zero segundos, mas novamente, o loop de eventos
‫realmente espera, então ele faz uma pausa na fase de votação.
‫E para que o retorno de
‫chamada setImmediate seja realmente executado primeiro, essa é a
‫razão pela qual temos esse imediato aqui depois de termos os temporizadores.
‫Ok, e eu sei que isso parece muito confuso, e
‫eu concordo totalmente, mas esse é apenas
‫o jeito do Node. js funciona.
‫E agora vamos tornar isso um pouco mais confuso e
‫adicionar o processo. nextTick que
‫falamos também na última aula.
‫Portanto, dizemos processo. nextTick e, como antes, simplesmente passamos uma
‫função de retorno de chamada.
‫E novamente, eu só quero fazer login
‫no console, e vou dizer processo. nextTick.
‫Então, o que você acha que vai acontecer neste caso?
‫Vá em frente e faça uma suposição e, quando estiver pronto, você
‫pode executar isso, então vamos fazer isso.
‫Salve-o aqui primeiro, execute-o e aqui vamos nós.
‫Portanto, os resultados estão novamente disponíveis, e agora o
‫primeiro retorno de chamada executado foi, na verdade, esta função aqui.
‫É por isso que temos processo. nextTick à
‫direita no primeiro.
‫Então, por que essa função de callback do processo. nextTick o primeiro
‫de todos eles a ser executado?
‫Bem, lembre-se de que nextTick
‫faz parte da fila de microtarefas, que são
‫executadas após cada fase, não apenas após um tick inteiro.
‫E então o que aconteceu aqui é que
‫essa função de retorno de chamada realmente foi executada antes da fase em que essa função
‫de retorno de chamada foi executada, e a fase anterior, tudo bem.
‫Agora nextTick é na verdade um nome enganoso, porque um tick
‫é na verdade um loop inteiro, mas nextTick
‫realmente acontece antes da próxima fase do loop, e não
‫de todo o tick, então é o que eu estava dizendo antes.
‫Então, por outro lado, setImmediate faria você pensar
‫que seu retorno de chamada seria executado imediatamente, mas
‫na verdade não é, certo, então
‫setImmediate é executado uma vez
‫por tick, enquanto nextTick é executado imediatamente.
‫E então seus dois nomes devem ser trocados.
‫Eles deveriam ser o contrário, e isso
‫pode causar muita confusão, então
‫é melhor sempre apenas se ater a um deles, e isso
‫geralmente é definido como imediato e não processado. nextTick.
‫De qualquer forma, como mencionei no último vídeo,
‫esses mecanismos são na verdade mais para casos de uso bastante
‫avançados, e é por isso
‫que provavelmente não os usaremos em nosso projeto.
‫Mas se você quiser aprender mais sobre
‫eles, você pode sempre ler a documentação oficial do Node.
‫Ok, então com isso simulamos alguns aspectos do
‫loop de evento, mas para terminar, quero apenas
‫introduzir rapidamente algo sobre o pool
‫de threads também e, para isso, faremos uma
‫operação mais complexa que será transferida para o
‫conjunto de encadeamentos e observe quanto tempo
‫essas operações levam para serem executadas e como podemos alterar o
‫tamanho do conjunto
‫de encadeamentos sobre o qual falamos antes.
‫Então, vamos usar um pouco
‫de criptografia aqui para criptografar basicamente uma senha.
‫Esse é um novo pacote que não
‫tínhamos usado antes e é chamado de Crypto, mas mencionei
‫antes que, na verdade, todas as funções deste pacote
‫serão descarregadas automaticamente pelo loop de eventos para o pool
‫de threads, e é isso que
‫nós vamos testar agora.
‫E vamos usar isso agora, então cripto. pb, então vamos usar uma
‫função de criptografia chamada pbkdf2, um nome meio estranho,
‫e agora passamos a string secreta, que digamos apenas senha,
‫então precisamos de uma string para resolver as senhas, e
‫as implementações aqui realmente não importa, então, por
‫enquanto, não vou entrar em nenhum detalhe de como
‫isso funciona, vamos fazer isso
‫mais tarde, ok, então aqui só precisamos do comprimento
‫da chave, então este número aqui
‫é apenas para
‫o número de iterações, então este é o comprimento da chave
‫e, finalmente, o algoritmo, que
‫será usado para criptografar a senha.
‫Portanto, esses números simplesmente aumentarão
‫o tempo necessário para a criptografia.
‫Ok e finalmente, também tem uma função de retorno de chamada, e tudo o que vou
‫fazer aqui é fazer outro console. log
‫e apenas diga a senha criptografada.
‫Agora, para o propósito desta
‫demonstração, eu realmente quero mostrar quanto tempo
‫cada uma dessas operações leva, então o
‫que vamos fazer é basicamente definir uma variável no
‫início, configurá-la como data. agora, então essa é a data atual em
‫milissegundos, e então aqui, tudo o que temos a fazer é registrar não
‫apenas a string, mas também a data. agora, que será a data
‫neste ponto em milissegundos, menos o início,
‫e isso nos dará a quantidade de
‫milissegundos que se passaram para
‫fazer este cálculo.
‫Ok, então vamos
‫experimentar, salve-o e execute-o novamente, e aqui você vê
‫que demorou 1855 milissegundos, ou seja,
‫quase dois segundos para criptografar essa senha.
‫Ok, mas agora vamos duplicar esse código ou,
‫na verdade, quero quatro instâncias
‫disso para mostrar algo a você.
‫Portanto, se executarmos isso agora, provavelmente levará aproximadamente a mesma
‫quantidade de tempo e, sim, leva, então
‫foi 1. 8
‫segundos, agora são 2. 2 segundos, o que é bastante semelhante.
‫Ok, e lembre-se que eu disse a você em
‫uma das palestras anteriores, que por
‫padrão o tamanho do pool de threads é
‫quatro, então há quatro threads fazendo o
‫trabalho ao mesmo tempo, e é por
‫isso que essas quatro criptografias de
‫senha demoram aproximadamente ao
‫mesmo tempo e acontecem basicamente ao mesmo tempo.
‫Mas podemos realmente alterar o tamanho do pool de threads.
‫Então, deixe-me mostrar como fazemos isso, e fazemos
‫isso dizendo processo. env, e
‫essa é uma variável de
‫ambiente, e mais uma vez falaremos mais
‫sobre isso mais tarde, e
‫UV, que significa LibUV, tamanho do threadpool, então se definirmos como um,
‫teremos apenas um thread em nosso pool de threads.
‫Então, vamos tentar de novo e ver o que acontece agora.
‫Então você vê que todos eles demoram muito mais para serem calculados.
‫Basicamente, eles são calculados um após o outro.
‫Então este é o primeiro, então este aqui leva o
‫dobro do tempo, e de novo isso
‫porque este só pode começar assim que o
‫primeiro estiver concluído, e o mesmo com
‫o terceiro e o quarto.
‫Agora digamos que mudemos
‫para dois, então devemos ver os
‫dois primeiros com o mesmo tempo, e exatamente,
‫os dois segundos também com um tempo semelhante.
‫Então isso faz sentido, certo.
‫Apenas para completar aqui,
‫agora o mesmo com três, então esses três têm um
‫tempo semelhante e, em seguida, o último.
‫Certo, é assim que o pool de threads funciona basicamente, então decidi
‫não apenas focar no loop de eventos, mas também
‫dar uma visão geral, muito rápida, do pool de threads e
‫como podemos alterar o tamanho do
‫pool de threads Ok, lembre-se de que
‫este código aqui ainda
‫é assíncrono, porque passamos uma função de retorno de chamada.
‫Ok, poderíamos realmente usar a versão síncrona, mas isso
‫bloquearia o loop de eventos.
‫Quer ver isso?
‫Então, deixe-me mostrar isso rapidamente para você também, então
‫aquele não foi realmente planejado, mas
‫vamos fazer assim mesmo, porque é muito
‫interessante ver isso, eu acho.
‫Ok, então isso vai funcionar assim.
‫Usamos novamente a versão de sincronização da mesma função, que
‫uma nota, está muitas vezes disponível.
‫Lembre-se de que temos o mesmo para o arquivo lido,
‫então lemos o arquivo, que aceita um retorno
‫de chamada, e lemos a sincronização de arquivo, que é a
‫versão síncrona que não aceita nenhum retorno de chamada, então assim.
‫Portanto, este irá criptografar a senha,
‫bloquear a execução do código e, em seguida, passar para a
‫próxima linha, que irá registrar isso aqui no console.
‫Então, vamos agora duplicar isso aqui.
‫Isso foi demais, livre-se deste aqui, e
‫agora essas quatro criptografias de senha não serão mais executadas
‫no loop de eventos.
‫E assim eles não serão mais descarregados para o pool de threads.
‫Ok, e agora mesmo se tivermos o tamanho do pool de
‫threads de quatro, vamos ver o que acontece.
‫Então você vê, eles acontecem completamente de forma síncrona.
‫Então, um após o outro, e o que é
‫ainda pior, é que
‫todos esses temporizadores aqui, mesmo nextTick e
‫o imediato, só apareceram depois que as criptografias de senha aconteceram.
‫Então isso realmente estava bloqueando toda a execução, mesmo se
‫este temporizador aqui, por exemplo este aqui, fosse
‫finalizado após zero segundos e este
‫após três segundos, mas
‫todos eles tiveram que esperar sete segundos
‫até que todas essas criptografias de senha
‫aqui fossem finalmente prontos, novamente porque eles não estavam sendo executados
‫dentro do loop de eventos, mas estavam.
‫E então eles estavam basicamente trabalhando em segundo plano
‫e só podiam ser
‫captados pelo loop de eventos quando estavam
‫prontos, logo após essas quatro criptografias de senha,
‫então este foi outro grande exemplo de ver
‫o bloqueio de código e o loop de eventos em ação.
‫Ok, isso foi o suficiente para uma palestra, espero que
‫você tenha achado interessante,
‫e vejo você na próxima.